<commit_before>#include <iostream>
#include <string>
#include <unistd.h>
#include <vector>
#include <atomic>
#include <signal.h>

#include <getopt.h>

#include "zcm/zcm-cpp.hpp"

using namespace std;

static atomic_int done {0};

static void sighandler(int signal)
{
    done++;
    if (done == 3) exit(1);
}

struct Args
{
    vector<string> Achannels;
    vector<string> Bchannels;

    string Aurl = "";
    string Burl = "";

    bool parse(int argc, char *argv[])
    {
        // set some defaults
        const char *optstring = "hA:B:a:b:";
        struct option long_opts[] = {
            { "help", no_argument, 0, 'h' },
            { "A-endpt", required_argument, 0, 'A'},
            { "B-endpt", required_argument, 0, 'B'},
            { "A-channel", required_argument, 0, 'a' },
            { "B-channel", required_argument, 0, 'b' },
            { 0, 0, 0, 0 }
        };

        int c;
        while ((c = getopt_long (argc, argv, optstring, long_opts, 0)) >= 0) {
            switch (c) {
                case 'A': Aurl = optarg; break;
                case 'B': Burl = optarg; break;
                case 'a': Achannels.push_back(optarg); break;
                case 'b': Bchannels.push_back(optarg); break;
                case 'h': default: return false;
            };
        }

        if (Aurl == "") {
            cerr << "Please specify A endpt url with the -A option" << endl;
            return false;
        }

        if (Burl == "") {
            cerr << "Please specify B endpt url with the -B option" << endl;
            return false;
        }

        if (Aurl == Burl) {
            cerr << "A and B endpoint urls must be unique" << endl;
            return false;
        }

        return true;
    }
};

struct Bridge
{
    Args   args;

    zcm::ZCM *zcmA = nullptr;
    zcm::ZCM *zcmB = nullptr;

    Bridge() {}

    ~Bridge()
    {
        if (zcmA) delete zcmA;
        if (zcmB) delete zcmB;
    }

    bool init(int argc, char *argv[])
    {
        if (!args.parse(argc, argv))
            return false;

        // A endpoint network
        zcmA = new zcm::ZCM(args.Aurl);
        if (!zcmA->good()) {
            cerr << "Couldn't initialize A endpoint ZCM network! "
                    "Please check your A endpoint transport url." << endl << endl;
            delete zcmA;
            zcmA = nullptr;
            return false;
        }

        // B endpoint network
        zcmB = new zcm::ZCM(args.Burl);
        if (!zcmB->good()) {
            cerr << "Couldn't initialize B endpoint ZCM network! "
                    "Please check your B endpoint transport url." << endl << endl;
            delete zcmB;
            zcmB = nullptr;
            return false;
        }

        return true;
    }

    static void handler(const zcm::ReceiveBuffer* rbuf, const string& channel, void* usr)
    {
        ((zcm::ZCM*)usr)->publish(channel, rbuf->data, rbuf->data_size);
    }

    void run()
    {
        if (args.Achannels.size() == 0) {
            zcmA->subscribe(".*", &handler, zcmB);
        } else {
            for (auto iter : args.Achannels)
                zcmA->subscribe(iter, &handler, zcmB);
        }

        if (args.Bchannels.size() == 0) {
            zcmB->subscribe(".*", &handler, zcmA);
        } else {
            for (auto iter : args.Bchannels)
                zcmB->subscribe(iter, &handler, zcmA);
        }

        zcmA->start();
        zcmB->start();

        while (!done) usleep(1e6);

        zcmA->stop();
        zcmB->stop();

        zcmA->flush();
        zcmB->flush();
    }
};

static void usage()
{
    cerr << "usage: zcm-bridge [options]" << endl
         << "" << endl
         << "    ZCM bridge utility. Bridges all data from one ZCM network to another." << endl
         << "" << endl
         << "Example:" << endl
         << "    zcm-bridge -A ipc -B udpm://239.255.76.67:7667?ttl=0" << endl
         << "" << endl
         << "Options:" << endl
         << "" << endl
         << "  -h, --help                 Shows this help text and exits" << endl
         << "  -A, --A-enpt=URL           One end of the bridge. Ex: zcm-bridge -A ipc" << endl
         << "  -B, --B-endpt=URL          One end of the bridge. Ex: zcm-bridge -B udpm://239.255.76.67:7667?ttl=0" << endl
         << "  -a, --A-channel=CHANNEL    One channel to subscribe to on A and repeat to B." << endl
         << "                             This argument can be specified multiple times. If this option is not," << endl
         << "                             present then we subscribe to all messages on the A interface." << endl
         << "                             Ex: zcm-bridge -A ipc -a EXAMPLE -B udpm://239.255.76.67:7667?ttl=0" << endl
         << "  -b, --B-channel=CHANNEL    One channel to subscribe to on B and repeat to A." << endl
         << "                             This argument can be specified multiple times. If this option is not," << endl
         << "                             present then we subscribe to all messages on the B interface." << endl
         << "                             Ex: zcm-bridge -A ipc -B udpm://239.255.76.67:7667?ttl=0 -b EXAMPLE" << endl
         << "" << endl << endl;
}

int main(int argc, char *argv[])
{
    Bridge bridge{};
    if (!bridge.init(argc, argv)) {
        usage();
        return 1;
    }

    // Register signal handlers
    signal(SIGINT, sighandler);
    signal(SIGQUIT, sighandler);
    signal(SIGTERM, sighandler);

    bridge.run();

    cerr << "Bridge exiting" << endl;

    return 0;
}
<commit_msg>added decimation and channel prefixing to zcm bridge<commit_after>#include <iostream>
#include <string>
#include <unistd.h>
#include <vector>
#include <atomic>
#include <signal.h>

#include <getopt.h>

#include "zcm/zcm-cpp.hpp"

using namespace std;

static atomic_int done {0};

static void sighandler(int signal)
{
    done++;
    if (done == 3) exit(1);
}

struct Args
{
    vector<string> Achannels;
    vector<string> Bchannels;

    vector<int> Adec;
    vector<int> Bdec;

    string Aurl = "";
    string Burl = "";

    string Aprefix = "";
    string Bprefix = "";

    bool parse(int argc, char *argv[])
    {
        // set some defaults
        const char *optstring = "hp:r:A:B:a:b:d:";
        struct option long_opts[] = {
            { "help",       no_argument, 0, 'h' },
            { "prefix-a",   required_argument, 0, 'p' },
            { "prefix-b",   required_argument, 0, 'r' },
            { "A-endpt",    required_argument, 0, 'A' },
            { "B-endpt",    required_argument, 0, 'B' },
            { "A-channel",  required_argument, 0, 'a' },
            { "B-channel",  required_argument, 0, 'b' },
            { "decimation", required_argument, 0, 'd' },
            { 0, 0, 0, 0 }
        };

        int c;
        vector<int> *currDec = nullptr;
        while ((c = getopt_long (argc, argv, optstring, long_opts, 0)) >= 0) {
            switch (c) {
                case 'p': currDec = nullptr; Aprefix = optarg; break;
                case 'r': currDec = nullptr; Bprefix = optarg; break;
                case 'A': currDec = nullptr; Aurl = optarg; break;
                case 'B': currDec = nullptr; Burl = optarg; break;
                case 'a':
                    Achannels.push_back(optarg);
                    Adec.push_back(0);
                    currDec = &Adec;
                    break;
                case 'b':
                    Bchannels.push_back(optarg);
                    Bdec.push_back(0);
                    currDec = &Bdec;
                    break;
                case 'd':
                    ZCM_ASSERT(currDec != nullptr &&
                               "Decimation must immediately follow a channel");
                    currDec->back() = atoi(optarg);
                    currDec = nullptr;
                    break;
                case 'h': default: return false;
            };
        }

        if (Aurl == "") {
            cerr << "Please specify A endpt url with the -A option" << endl;
            return false;
        }

        if (Burl == "") {
            cerr << "Please specify B endpt url with the -B option" << endl;
            return false;
        }

        if (Aurl == Burl) {
            cerr << "A and B endpoint urls must be unique" << endl;
            return false;
        }

        return true;
    }
};

struct Bridge
{
    Args   args;

    zcm::ZCM *zcmA = nullptr;
    zcm::ZCM *zcmB = nullptr;

    struct BridgeInfo {
        zcm::ZCM *zcmOut = nullptr;
        string    prefix = "";
        int       decimation = 0;
        int       nSkipped = 0;

        BridgeInfo(zcm::ZCM* zcmOut, const string &prefix, int dec) :
            zcmOut(zcmOut), prefix(prefix), decimation(dec), nSkipped(0) {}

        BridgeInfo() {}
    };

    Bridge() {}

    ~Bridge()
    {
        if (zcmA) delete zcmA;
        if (zcmB) delete zcmB;
    }

    bool init(int argc, char *argv[])
    {
        if (!args.parse(argc, argv))
            return false;

        // A endpoint network
        zcmA = new zcm::ZCM(args.Aurl);
        if (!zcmA->good()) {
            cerr << "Couldn't initialize A endpoint ZCM network! "
                    "Please check your A endpoint transport url." << endl << endl;
            delete zcmA;
            zcmA = nullptr;
            return false;
        }

        // B endpoint network
        zcmB = new zcm::ZCM(args.Burl);
        if (!zcmB->good()) {
            cerr << "Couldn't initialize B endpoint ZCM network! "
                    "Please check your B endpoint transport url." << endl << endl;
            delete zcmB;
            zcmB = nullptr;
            return false;
        }

        return true;
    }

    static void handler(const zcm::ReceiveBuffer* rbuf, const string& channel, void* usr)
    {
        BridgeInfo* info = (BridgeInfo*)usr;
        if (info->nSkipped == info->decimation) {
            string newChannel = info->prefix + channel;
            info->zcmOut->publish(newChannel, rbuf->data, rbuf->data_size);
            info->nSkipped = 0;
        } else {
            info->nSkipped++;
        }
    }

    void run()
    {
        vector<BridgeInfo> infoA, infoB;

        infoA.reserve(args.Achannels.size());
        infoB.reserve(args.Bchannels.size());

        BridgeInfo defaultA(zcmB, args.Bprefix, 0),
                   defaultB(zcmA, args.Aprefix, 0);

        if (args.Achannels.size() == 0) {
            zcmA->subscribe(".*", &handler, &defaultA);
        } else {
            for (size_t i = 0; i < args.Achannels.size(); i++) {
                infoA.emplace_back(zcmB, args.Bprefix, args.Adec.at(i));
                zcmA->subscribe(args.Achannels.at(i), &handler, &infoA.back());
            }
        }

        if (args.Bchannels.size() == 0) {
            zcmB->subscribe(".*", &handler, &defaultB);
        } else {
            for (size_t i = 0; i < args.Bchannels.size(); i++) {
                infoB.emplace_back(zcmA, args.Aprefix, args.Bdec.at(i));
                zcmB->subscribe(args.Bchannels.at(i), &handler, &infoB.back());
            }
        }

        ZCM_ASSERT(infoA.size() == args.Achannels.size() &&
                   infoA.size() == args.Adec.size() &&
                   infoB.size() == args.Bchannels.size() &&
                   infoB.size() == args.Bdec.size());

        zcmA->start();
        zcmB->start();

        while (!done) usleep(1e6);

        zcmA->stop();
        zcmB->stop();

        zcmA->flush();
        zcmB->flush();
    }
};

static void usage()
{
    cerr << "usage: zcm-bridge [options]" << endl
         << "" << endl
         << "    ZCM bridge utility. Bridges all data from one ZCM network to another." << endl
         << "" << endl
         << "Example:" << endl
         << "    zcm-bridge -A ipc -B udpm://239.255.76.67:7667?ttl=0" << endl
         << "" << endl
         << "Options:" << endl
         << "" << endl
         << "  -h, --help                 Shows this help text and exits" << endl
         << "  -A, --A-enpt=URL           One end of the bridge. Ex: zcm-bridge -A ipc" << endl
         << "  -B, --B-endpt=URL          One end of the bridge. Ex: zcm-bridge -B udpm://239.255.76.67:7667?ttl=0" << endl
         << "  -p, --prefix-a             Specify a prefix for all messages published on the A url" << endl
         << "  -r, --prefix-b             Specify a prefix for all messages published on the B url" << endl
         << "  -a, --A-channel=CHANNEL    One channel to subscribe to on A and repeat to B." << endl
         << "                             This argument can be specified multiple times. If this option is not," << endl
         << "                             present then we subscribe to all messages on the A interface." << endl
         << "                             Ex: zcm-bridge -A ipc -a EXAMPLE -B udpm://239.255.76.67:7667?ttl=0" << endl
         << "  -b, --B-channel=CHANNEL    One channel to subscribe to on B and repeat to A." << endl
         << "                             This argument can be specified multiple times. If this option is not," << endl
         << "                             present then we subscribe to all messages on the B interface." << endl
         << "                             Ex: zcm-bridge -A ipc -B udpm://239.255.76.67:7667?ttl=0 -b EXAMPLE" << endl
         << "  -d, --decimation           Decimation level for the preceeding A-channel or B-channel. " << endl
         << "                             Ex: zcm-bridge -A ipc -B udpm://239.255.76.67:7667?ttl=0 -b EXAMPLE -d 2" << endl
         << "                             This example would result in the message on EXAMPLE being rebroadcast on" << endl
         << "                             the A url every third message." << endl
         << "" << endl << endl;
}

int main(int argc, char *argv[])
{
    Bridge bridge{};
    if (!bridge.init(argc, argv)) {
        usage();
        return 1;
    }

    // Register signal handlers
    signal(SIGINT, sighandler);
    signal(SIGQUIT, sighandler);
    signal(SIGTERM, sighandler);

    bridge.run();

    cerr << "Bridge exiting" << endl;

    return 0;
}
<|endoftext|>


<commit_before>#include "Common.hpp"
#include "MsgDisplay.hpp"
#include "TypeDb.hpp"
#include "MsgInfo.hpp"
#include "Debug.hpp"

#define SELECT_TIMEOUT 20000
#define ESCAPE_KEY 0x1B
#define DEL_KEY 0x7f

static volatile bool quit = false;

enum class DisplayMode {
    Overview, Decode,
};

struct SpyInfo
{
    SpyInfo(const char *path, bool debug)
    : typedb(path, debug)
    {
    }

    ~SpyInfo()
    {
        for (auto& it : minfomap)
            delete it.second;
    }

    MsgInfo *getCurrentMsginfo(const char **channel)
    {
        auto& ch = names[decode_index];
        MsgInfo **m = lookup(minfomap, ch);
        assert(m);
        if (channel)
            *channel = ch.c_str();
        return *m;
    }

    bool isValidChannelnum(size_t index)
    {
        return (0 <= index && index < names.size());
    }

    void addMessage(const char *channel, const zcm_recv_buf_t *rbuf);

    void display();
    void displayOverview();

    void handleKeyboard(char ch);
    void handleKeyboardOverview(char ch);
    void handleKeyboardDecode(char ch);

private:
    vector<string>                  names;
    unordered_map<string, MsgInfo*> minfomap;
    TypeDb typedb;

    mutex mut;

    DisplayMode mode = DisplayMode::Overview;
    bool is_selecting = false;

    int decode_index = 0;
    MsgInfo *decode_msg_info;
    const char *decode_msg_channel;
};

void SpyInfo::addMessage(const char *channel, const zcm_recv_buf_t *rbuf)
{
    unique_lock<mutex> lk(mut);

    MsgInfo *minfo = minfomap[channel];
    if (minfo == NULL) {
        minfo = new MsgInfo(typedb, channel);
        names.push_back(channel);
        std::sort(begin(names), end(names));
        minfomap[channel] = minfo;
    }
    minfo->addMessage(TimeUtil::utime(), rbuf);
}

void SpyInfo::display()
{
    unique_lock<mutex> lk(mut);

    switch (mode) {
        case DisplayMode::Overview: {
            displayOverview();
        } break;
        case DisplayMode::Decode: {
            decode_msg_info->display();
        } break;
        default:
            DEBUG(1, "ERR: unknown mode\n");
    }
}

void SpyInfo::displayOverview()
{
    printf("         %-28s\t%12s\t%8s\n", "Channel", "Num Messages", "Hz (ave)");
    printf("   ----------------------------------------------------------------\n");

    DEBUG(5, "start-loop\n");

    for (size_t i = 0; i < names.size(); i++) {
        auto& channel = names[i];
        MsgInfo **minfo = lookup(minfomap, channel);
        assert(minfo != NULL);
        float hz = (*minfo)->getHertz();
        printf("   %3zu)  %-28s\t%9" PRIu64 "\t%7.2f\n", i, channel.c_str(), (*minfo)->getNumMsgs(), hz);
    }

    printf("\n");

    if (is_selecting) {
        printf("   Decode channel: ");
        if (decode_index != -1)
            printf("%d", decode_index);
        fflush(stdout);
    }
}

void SpyInfo::handleKeyboardOverview(char ch)
{
    if (ch == '-') {
        is_selecting = true;
        decode_index = -1;
    } else if ('0' <= ch && ch <= '9') {
        // shortcut for single digit channels
        if (!is_selecting) {
            decode_index = ch - '0';
            if (isValidChannelnum(decode_index)) {
                decode_msg_info = getCurrentMsginfo(&decode_msg_channel);
                mode = DisplayMode::Decode;
            }
        } else {
            if (decode_index == -1) {
                decode_index = ch - '0';
            } else if (decode_index < 10000) {
                decode_index *= 10;
                decode_index += (ch - '0');
            }
        }
    } else if (ch == '\n') {
        if (is_selecting) {
            if (isValidChannelnum(decode_index)) {
                decode_msg_info = getCurrentMsginfo(&decode_msg_channel);
                mode = DisplayMode::Decode;
            }
            is_selecting = false;
        }
    } else if (ch == '\b' || ch == DEL_KEY) {
        if (is_selecting) {
            if (decode_index < 10)
                decode_index = -1;
            else
                decode_index /= 10;
        }
    } else {
        DEBUG(1, "INFO: unrecognized input: '%c' (0x%2x)\n", ch, ch);
    }
}

void SpyInfo::handleKeyboardDecode(char ch)
{
    MsgInfo& minfo = *decode_msg_info;
    size_t depth = minfo.getViewDepth();

    if (ch == ESCAPE_KEY) {
        if (depth > 0) {
            minfo.decViewDepth();
        } else {
            mode = DisplayMode::Overview;
        }
    } else if ('0' <= ch && ch <= '9') {
        // if number is pressed, set and increase sub-msg decoding depth
        size_t viewid = (ch - '0');
        if (depth < MSG_DISPLAY_RECUR_MAX) {
            minfo.incViewDepth(viewid);
        } else {
            DEBUG(1, "INFO: cannot recurse further: reached maximum depth of %d\n",
                  MSG_DISPLAY_RECUR_MAX);
        }
    } else {
        DEBUG(1, "INFO: unrecognized input: '%c' (0x%2x)\n", ch, ch);
    }
}

void SpyInfo::handleKeyboard(char ch)
{
    unique_lock<mutex> lk(mut);

    switch (mode) {
        case DisplayMode::Overview: handleKeyboardOverview(ch); break;
        case DisplayMode::Decode:   handleKeyboardDecode(ch);  break;
        default:
            DEBUG(1, "INFO: unrecognized keyboard mode: %d\n", (int)mode);
    }
}

void *keyboard_thread_func(void *arg)
{
    SpyInfo *spy = (SpyInfo *)arg;

    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
        perror("tcsetattr()");

    struct termios newt = old;
    newt.c_lflag &= ~ICANON;
    newt.c_lflag &= ~ECHO;
    newt.c_cc[VMIN] = 1;
    newt.c_cc[VTIME] = 0;
    if (tcsetattr(0, TCSANOW, &newt) < 0)
        perror("tcsetattr ICANON");

    char ch;
    while(!quit) {
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(0, &fds);

        struct timeval timeout = { 0, SELECT_TIMEOUT };
        int status = select(1, &fds, 0, 0, &timeout);

        if(quit)
            break;

        if(status != 0 && FD_ISSET(0, &fds)) {

            if(read(0, &ch, 1) < 0)
                perror ("read()");

            spy->handleKeyboard(ch);

        } else {
            DEBUG(4, "INFO: keyboard_thread_func select() timeout\n");
        }
    }

    if (tcsetattr(0, TCSADRAIN, &old) < 0)
        perror ("tcsetattr ~ICANON");

    return NULL;
}
//////////////////////////////////////////////////////////////////////
////////////////////////// Helper Functions //////////////////////////
//////////////////////////////////////////////////////////////////////

void clearscreen()
{
    // clear
    printf("\033[2J");

    // move cursor to (0, 0)
    printf("\033[0;0H");
}

//////////////////////////////////////////////////////////////////////
//////////////////////////// Print Thread ////////////////////////////
//////////////////////////////////////////////////////////////////////

void printThreadFunc(SpyInfo *spy)
{
    static constexpr float hz = 20.0;
    static constexpr u64 period = 1000000 / hz;

    DEBUG(1, "INFO: %s: Starting\n", "print_thread");
    while (!quit) {
        usleep(period);

        clearscreen();
        printf("  **************************************************************************** \n");
        printf("  ******************************* ZCM-SPY-LITE ******************************* \n");
        printf("  **************************************************************************** \n");

        spy->display();

        // flush the stdout buffer (required since we use full buffering)
        fflush(stdout);
    }

    DEBUG(1, "INFO: %s: Ending\n", "print_thread");
}

//////////////////////////////////////////////////////////////////////
///////////////////////////// LCM HANDLER ////////////////////////////
//////////////////////////////////////////////////////////////////////

void handler_all_zcm (const zcm_recv_buf_t *rbuf,
                      const char *channel, void *arg)
{
    SpyInfo *spy = (SpyInfo *)arg;
    spy->addMessage(channel, rbuf);
}

//////////////////////////////////////////////////////////////////////
////////////////////////////////// MAIN //////////////////////////////
//////////////////////////////////////////////////////////////////////

static void sighandler(int s)
{
    switch(s) {
        case SIGQUIT:
        case SIGINT:
        case SIGTERM:
            DEBUG(1, "Caught signal...\n");
            quit = true;
            break;
        default:
            DEBUG(1, "WRN: unrecognized signal fired\n");
            break;
    }
}

int main(int argc, char *argv[])
{
    DEBUG_INIT();
    bool debug = false;

    // XXX get opt
    if(argc > 1 && strcmp(argv[1], "--debug") == 0)
        debug = true;

    // get the zcmtypes.so from ZCM_SPY_LITE_PATH
    const char *spy_lite_path = getenv("ZCM_SPY_LITE_PATH");
    if (debug)
        printf("zcm_spy_lite_path='%s'\n", spy_lite_path);
    if (spy_lite_path == NULL) {
        fprintf(stderr, "ERR: invalid $ZCM_SPY_LITE_PATH\n");
        return 1;
    }

    SpyInfo spy {spy_lite_path, debug};
    if (debug)
        exit(0);

    signal(SIGINT, sighandler);
    signal(SIGQUIT, sighandler);
    signal(SIGTERM, sighandler);

    // configure stdout buffering: use FULL buffering to avoid flickering
    setvbuf(stdout, NULL, _IOFBF, 2048);

    // start zcm
    zcm_t *zcm = zcm_create(NULL);
    if (!zcm) {
        DEBUG(1, "ERR: failed to create an zcm object!\n");
        return 1;
    }
    zcm_subscribe(zcm, ".*", handler_all_zcm, &spy);
    zcm_start(zcm);

    thread printThread {printThreadFunc, &spy};

    // use this thread as the keyboard thread
    keyboard_thread_func(&spy);

    // cleanup
    printThread.join();
    zcm_stop(zcm);

    DEBUG(1, "Exiting...\n");
    return 0;
}
<commit_msg>Now accepts multidigit field decoding via dash operator<commit_after>#include "Common.hpp"
#include "MsgDisplay.hpp"
#include "TypeDb.hpp"
#include "MsgInfo.hpp"
#include "Debug.hpp"

#define SELECT_TIMEOUT 20000
#define ESCAPE_KEY 0x1B
#define DEL_KEY 0x7f

static volatile bool quit = false;

enum class DisplayMode {
    Overview, Decode,
};

struct SpyInfo
{
    SpyInfo(const char *path, bool debug)
    : typedb(path, debug)
    {
    }

    ~SpyInfo()
    {
        for (auto& it : minfomap)
            delete it.second;
    }

    MsgInfo *getCurrentMsginfo(const char **channel)
    {
        auto& ch = names[decode_index];
        MsgInfo **m = lookup(minfomap, ch);
        assert(m);
        if (channel)
            *channel = ch.c_str();
        return *m;
    }

    bool isValidChannelnum(size_t index)
    {
        return (0 <= index && index < names.size());
    }

    void addMessage(const char *channel, const zcm_recv_buf_t *rbuf);

    void display();
    void displayOverview();

    void handleKeyboard(char ch);
    void handleKeyboardOverview(char ch);
    void handleKeyboardDecode(char ch);

private:
    vector<string>                  names;
    unordered_map<string, MsgInfo*> minfomap;
    TypeDb typedb;

    mutex mut;

    DisplayMode mode = DisplayMode::Overview;
    bool is_selecting = false;

    int decode_index = 0;
    MsgInfo *decode_msg_info;
    const char *decode_msg_channel;
    int view_id;
};

void SpyInfo::addMessage(const char *channel, const zcm_recv_buf_t *rbuf)
{
    unique_lock<mutex> lk(mut);

    MsgInfo *minfo = minfomap[channel];
    if (minfo == NULL) {
        minfo = new MsgInfo(typedb, channel);
        names.push_back(channel);
        std::sort(begin(names), end(names));
        minfomap[channel] = minfo;
    }
    minfo->addMessage(TimeUtil::utime(), rbuf);
}

void SpyInfo::display()
{
    unique_lock<mutex> lk(mut);

    switch (mode) {
        case DisplayMode::Overview: {
            displayOverview();
        } break;
        case DisplayMode::Decode: {
            decode_msg_info->display();

            if (is_selecting) {
                printf("   Decode field: ");
                if (view_id != -1)
                    printf("%d", view_id );
                fflush(stdout);
            }
        } break;
        default:
            DEBUG(1, "ERR: unknown mode\n");
    }
}

void SpyInfo::displayOverview()
{
    printf("         %-28s\t%12s\t%8s\n", "Channel", "Num Messages", "Hz (ave)");
    printf("   ----------------------------------------------------------------\n");

    DEBUG(5, "start-loop\n");

    for (size_t i = 0; i < names.size(); i++) {
        auto& channel = names[i];
        MsgInfo **minfo = lookup(minfomap, channel);
        assert(minfo != NULL);
        float hz = (*minfo)->getHertz();
        printf("   %3zu)  %-28s\t%9" PRIu64 "\t%7.2f\n", i, channel.c_str(), (*minfo)->getNumMsgs(), hz);
    }

    printf("\n");

    if (is_selecting) {
        printf("   Decode channel: ");
        if (decode_index != -1)
            printf("%d", decode_index);
        fflush(stdout);
    }
}

void SpyInfo::handleKeyboardOverview(char ch)
{
    if (ch == '-') {
        is_selecting = true;
        decode_index = -1;
    } else if ('0' <= ch && ch <= '9') {
        // shortcut for single digit channels
        if (!is_selecting) {
            decode_index = ch - '0';
            if (isValidChannelnum(decode_index)) {
                decode_msg_info = getCurrentMsginfo(&decode_msg_channel);
                mode = DisplayMode::Decode;
            }
        } else {
            if (decode_index == -1) {
                decode_index = ch - '0';
            } else if (decode_index < 10000) {
                decode_index *= 10;
                decode_index += (ch - '0');
            }
        }
    } else if (ch == '\n') {
        if (is_selecting) {
            if (isValidChannelnum(decode_index)) {
                decode_msg_info = getCurrentMsginfo(&decode_msg_channel);
                mode = DisplayMode::Decode;
            }
            is_selecting = false;
        }
    } else if (ch == '\b' || ch == DEL_KEY) {
        if (is_selecting) {
            if (decode_index < 10)
                decode_index = -1;
            else
                decode_index /= 10;
        }
    } else {
        DEBUG(1, "INFO: unrecognized input: '%c' (0x%2x)\n", ch, ch);
    }
}

void SpyInfo::handleKeyboardDecode(char ch)
{
    MsgInfo& minfo = *decode_msg_info;
    size_t depth = minfo.getViewDepth();

    if (ch == ESCAPE_KEY) {
        if (depth > 0) {
            minfo.decViewDepth();
        } else {
            mode = DisplayMode::Overview;
        }
        is_selecting = false;
    } else if (ch == '-') {
        is_selecting = true;
        view_id = -1;
    } else if ('0' <= ch && ch <= '9') {
        // shortcut for single digit channels
        if (!is_selecting) {
            view_id = ch - '0';
            // set and increase sub-msg decoding depth
            if (depth < MSG_DISPLAY_RECUR_MAX) {
                minfo.incViewDepth(view_id);
            } else {
                DEBUG(1, "INFO: cannot recurse further: reached maximum depth of %d\n",
                      MSG_DISPLAY_RECUR_MAX);
            }
        } else {
            if (view_id == -1) {
                view_id = ch - '0';
            } else if (view_id < 10000) {
                view_id *= 10;
                view_id += (ch - '0');
            }
        }
    } else if (ch == '\n') {
        if (is_selecting) {
            // set and increase sub-msg decoding depth
            if (depth < MSG_DISPLAY_RECUR_MAX) {
                minfo.incViewDepth(view_id);
            } else {
                DEBUG(1, "INFO: cannot recurse further: reached maximum depth of %d\n",
                      MSG_DISPLAY_RECUR_MAX);
            }
            is_selecting = false;
        }
    } else if (ch == '\b' || ch == DEL_KEY) {
        if (is_selecting) {
            if (view_id < 10)
                view_id = -1;
            else
                view_id /= 10;
        }
    } else {
        DEBUG(1, "INFO: unrecognized input: '%c' (0x%2x)\n", ch, ch);
    }
}

void SpyInfo::handleKeyboard(char ch)
{
    unique_lock<mutex> lk(mut);

    switch (mode) {
        case DisplayMode::Overview: handleKeyboardOverview(ch); break;
        case DisplayMode::Decode:   handleKeyboardDecode(ch);  break;
        default:
            DEBUG(1, "INFO: unrecognized keyboard mode: %d\n", (int)mode);
    }
}

void *keyboard_thread_func(void *arg)
{
    SpyInfo *spy = (SpyInfo *)arg;

    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
        perror("tcsetattr()");

    struct termios newt = old;
    newt.c_lflag &= ~ICANON;
    newt.c_lflag &= ~ECHO;
    newt.c_cc[VMIN] = 1;
    newt.c_cc[VTIME] = 0;
    if (tcsetattr(0, TCSANOW, &newt) < 0)
        perror("tcsetattr ICANON");

    char ch;
    while(!quit) {
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(0, &fds);

        struct timeval timeout = { 0, SELECT_TIMEOUT };
        int status = select(1, &fds, 0, 0, &timeout);

        if(quit)
            break;

        if(status != 0 && FD_ISSET(0, &fds)) {

            if(read(0, &ch, 1) < 0)
                perror ("read()");

            spy->handleKeyboard(ch);

        } else {
            DEBUG(4, "INFO: keyboard_thread_func select() timeout\n");
        }
    }

    if (tcsetattr(0, TCSADRAIN, &old) < 0)
        perror ("tcsetattr ~ICANON");

    return NULL;
}
//////////////////////////////////////////////////////////////////////
////////////////////////// Helper Functions //////////////////////////
//////////////////////////////////////////////////////////////////////

void clearscreen()
{
    // clear
    printf("\033[2J");

    // move cursor to (0, 0)
    printf("\033[0;0H");
}

//////////////////////////////////////////////////////////////////////
//////////////////////////// Print Thread ////////////////////////////
//////////////////////////////////////////////////////////////////////

void printThreadFunc(SpyInfo *spy)
{
    static constexpr float hz = 20.0;
    static constexpr u64 period = 1000000 / hz;

    DEBUG(1, "INFO: %s: Starting\n", "print_thread");
    while (!quit) {
        usleep(period);

        clearscreen();
        printf("  **************************************************************************** \n");
        printf("  ******************************* ZCM-SPY-LITE ******************************* \n");
        printf("  **************************************************************************** \n");

        spy->display();

        // flush the stdout buffer (required since we use full buffering)
        fflush(stdout);
    }

    DEBUG(1, "INFO: %s: Ending\n", "print_thread");
}

//////////////////////////////////////////////////////////////////////
///////////////////////////// LCM HANDLER ////////////////////////////
//////////////////////////////////////////////////////////////////////

void handler_all_zcm (const zcm_recv_buf_t *rbuf,
                      const char *channel, void *arg)
{
    SpyInfo *spy = (SpyInfo *)arg;
    spy->addMessage(channel, rbuf);
}

//////////////////////////////////////////////////////////////////////
////////////////////////////////// MAIN //////////////////////////////
//////////////////////////////////////////////////////////////////////

static void sighandler(int s)
{
    switch(s) {
        case SIGQUIT:
        case SIGINT:
        case SIGTERM:
            DEBUG(1, "Caught signal...\n");
            quit = true;
            break;
        default:
            DEBUG(1, "WRN: unrecognized signal fired\n");
            break;
    }
}

int main(int argc, char *argv[])
{
    DEBUG_INIT();
    bool debug = false;

    // XXX get opt
    if(argc > 1 && strcmp(argv[1], "--debug") == 0)
        debug = true;

    // get the zcmtypes.so from ZCM_SPY_LITE_PATH
    const char *spy_lite_path = getenv("ZCM_SPY_LITE_PATH");
    if (debug)
        printf("zcm_spy_lite_path='%s'\n", spy_lite_path);
    if (spy_lite_path == NULL) {
        fprintf(stderr, "ERR: invalid $ZCM_SPY_LITE_PATH\n");
        return 1;
    }

    SpyInfo spy {spy_lite_path, debug};
    if (debug)
        exit(0);

    signal(SIGINT, sighandler);
    signal(SIGQUIT, sighandler);
    signal(SIGTERM, sighandler);

    // configure stdout buffering: use FULL buffering to avoid flickering
    setvbuf(stdout, NULL, _IOFBF, 2048);

    // start zcm
    zcm_t *zcm = zcm_create(NULL);
    if (!zcm) {
        DEBUG(1, "ERR: failed to create an zcm object!\n");
        return 1;
    }
    zcm_subscribe(zcm, ".*", handler_all_zcm, &spy);
    zcm_start(zcm);

    thread printThread {printThreadFunc, &spy};

    // use this thread as the keyboard thread
    keyboard_thread_func(&spy);

    // cleanup
    printThread.join();
    zcm_stop(zcm);

    DEBUG(1, "Exiting...\n");
    return 0;
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
//---
//  Produces the data needed to calculate the quality assurance.
//  All data must be mergeable objects.

//  Authors:
//
//  Luciano Diaz Gonzalez <luciano.diaz@nucleares.unam.mx> (ICN-UNAM)
//  Mario Rodriguez Cahuantzi <mrodrigu@mail.cern.ch> (FCFM-BUAP)
//  Arturo Fernandez Tellez <afernan@mail.cern.ch (FCFM-BUAP)
//
//  Created: June 13th 2008
//---
// Last Update: Aug. 27th 2008 --> Implementation to declare QA expert histogram

// --- ROOT system ---
#include <TClonesArray.h>
#include <TFile.h>
#include <TH1F.h>
#include <TDirectory.h>
// --- Standard library ---

// --- AliRoot header files ---
#include "AliESDEvent.h"
#include "AliLog.h"
#include "AliACORDEdigit.h"
#include "AliACORDEhit.h"
#include "AliACORDEQADataMakerRec.h"
#include "AliQAChecker.h"
#include "AliACORDERawReader.h"
#include "AliACORDERawStream.h"
ClassImp(AliACORDEQADataMakerRec)

//____________________________________________________________________________
AliACORDEQADataMakerRec::AliACORDEQADataMakerRec():AliQADataMakerRec(AliQA::GetDetName(AliQA::kACORDE), "ACORDE Quality Assurance Data Maker")
{

}
//____________________________________________________________________________
AliACORDEQADataMakerRec::AliACORDEQADataMakerRec(const AliACORDEQADataMakerRec& qadm):AliQADataMakerRec()
{
  SetName((const char*)qadm.GetName()) ;
  SetTitle((const char*)qadm.GetTitle());
}
//__________________________________________________________________
AliACORDEQADataMakerRec& AliACORDEQADataMakerRec::operator = (const AliACORDEQADataMakerRec& qadm )
{
  // Equal operator.
  this->~AliACORDEQADataMakerRec();
  new(this) AliACORDEQADataMakerRec(qadm);
  return *this;
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::EndOfDetectorCycle(AliQA::TASKINDEX_t task, TObjArray * list)
{
  //Detector specific actions at end of cycle
  // do the QA checking
  AliQAChecker::Instance()->Run(AliQA::kACORDE, task, list) ;
}

//____________________________________________________________________________
void AliACORDEQADataMakerRec::StartOfDetectorCycle()
{
  //Detector specific actions at start of cycle

}

//____________________________________________________________________________
void AliACORDEQADataMakerRec::InitRaws()
{
  // create Raw histograms in Raw subdir

TH1D *fhACORDEBitPattern[4];
fhACORDEBitPattern[0] = new TH1D("ACORDERawDataSM","ACORDE-SingleMuon",60,1,60);//AcordeSingleMuon BitPattern
fhACORDEBitPattern[1] = new TH1D("ACORDERawDataMM","ACORDE-MultiMuon",60,1,60);//AcordeMultiMuon BitPattern
fhACORDEBitPattern[2] = new TH1D("ACORDERawDataSMM","ACORDE-SingleMuonMultiplicity",60,1,60);//AcordeSingleMuon Multiplicity
fhACORDEBitPattern[3] = new TH1D("ACORDERawDataMMM","ACORDE-MultiMuonMultiplicity",60,1,60);//AcordeMultiMuon Multiplicity
for(Int_t i=0;i<4;i++)
{
	Add2RawsList(fhACORDEBitPattern[i],i,kFALSE);
}
}
//____________________________________________________________________________

void AliACORDEQADataMakerRec::InitRecPoints()
{
  // create cluster histograms in RecPoint subdir
  // Not needed for ACORDE by now !!!
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::InitESDs()
{
  //create ESDs histograms in ESDs subdir

   TH1F *    fhESDsSingle;
   TH1F *    fhESDsMulti;

   TString   name;

   name = "hESDsSingle";
   fhESDsSingle = new TH1F(name.Data(),"hESDsSingle",60,0,60);
   Add2ESDsList(fhESDsSingle,0,kFALSE);

   name = "hESDsMulti";
   fhESDsMulti = new TH1F(name.Data(),"hESDsMulti",60,0,60);
   Add2ESDsList(fhESDsMulti,1,kFALSE);
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::MakeRaws(AliRawReader* rawReader)
{
  //fills QA histos for RAW
  rawReader->Reset();
  AliACORDERawStream rawStream(rawReader);
  size_t contSingle=0;
  size_t contMulti=0;
  UInt_t dy[4];

  bool kroSingle[60],kroMulti[60];
  UInt_t tmpDy;

  for(Int_t m=0;m<60;m++) {kroSingle[m]=0;kroMulti[m]=0;}

if(rawStream.Next())
{
	rawReader->NextEvent();
        rawStream.Reset();
        dy[0]=rawStream.GetWord(0);
        dy[1]=rawStream.GetWord(1);
        dy[2]=rawStream.GetWord(2);
        dy[3]=rawStream.GetWord(3);
        tmpDy=dy[0];
        for(Int_t r=0;r<30;++r)
        {
                kroSingle[r] = tmpDy & 1;
                tmpDy>>=1;
        }
        tmpDy=dy[1];
        for(Int_t r=30;r<60;++r)
        {
                kroSingle[r] = tmpDy & 1;
                tmpDy>>=1;
        }
        tmpDy=dy[2];
        for(Int_t r=0;r<30;++r)
        {
                kroMulti[r] = tmpDy & 1;
                tmpDy>>=1;
        }
        tmpDy=dy[3];
        for(Int_t r=30;r<60;++r)
        {
                kroMulti[r] = tmpDy & 1;
                tmpDy>>=1;
        }
        contSingle=0;
	contMulti=0;
        for(Int_t r=0;r<60;++r)
        {
                if(kroSingle[r]==1)
                {
                        GetRawsData(0)->Fill(r+1);
                        contSingle=contSingle+1;
                }
		if(kroMulti[r]==1)
		{
			GetRawsData(1)->Fill(r+1);
			contMulti++;
		}

        }GetRawsData(2)->Fill(contSingle);GetRawsData(3)->Fill(contMulti);
}
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::MakeRecPoints(TTree * clustersTree)
{
  //fills QA histos for clusters
  // Not needed for ACORDE by now !!!
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::MakeESDs(AliESDEvent * esd)
{
  //fills QA histos for ESD

        AliESDACORDE * fESDACORDE= esd->GetACORDEData();
        Int_t *fACORDEMultiMuon =fESDACORDE->GetACORDEMultiMuon();
        Int_t *fACORDESingleMuon=fESDACORDE->GetACORDESingleMuon();

       for(int i=0;i<60;i++){
            if(fACORDESingleMuon[i]==1)
               GetESDsData(0) -> Fill(i);
            if(fACORDEMultiMuon[i]==1)
               GetESDsData(1) -> Fill(i);
        }

}

<commit_msg>Crucial bug-fix. The raw-data events should be never skipped inside the QA data makers<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
//---
//  Produces the data needed to calculate the quality assurance.
//  All data must be mergeable objects.

//  Authors:
//
//  Luciano Diaz Gonzalez <luciano.diaz@nucleares.unam.mx> (ICN-UNAM)
//  Mario Rodriguez Cahuantzi <mrodrigu@mail.cern.ch> (FCFM-BUAP)
//  Arturo Fernandez Tellez <afernan@mail.cern.ch (FCFM-BUAP)
//
//  Created: June 13th 2008
//---
// Last Update: Aug. 27th 2008 --> Implementation to declare QA expert histogram

// --- ROOT system ---
#include <TClonesArray.h>
#include <TFile.h>
#include <TH1F.h>
#include <TDirectory.h>
// --- Standard library ---

// --- AliRoot header files ---
#include "AliESDEvent.h"
#include "AliLog.h"
#include "AliACORDEdigit.h"
#include "AliACORDEhit.h"
#include "AliACORDEQADataMakerRec.h"
#include "AliQAChecker.h"
#include "AliACORDERawReader.h"
#include "AliACORDERawStream.h"
ClassImp(AliACORDEQADataMakerRec)

//____________________________________________________________________________
AliACORDEQADataMakerRec::AliACORDEQADataMakerRec():AliQADataMakerRec(AliQA::GetDetName(AliQA::kACORDE), "ACORDE Quality Assurance Data Maker")
{

}
//____________________________________________________________________________
AliACORDEQADataMakerRec::AliACORDEQADataMakerRec(const AliACORDEQADataMakerRec& qadm):AliQADataMakerRec()
{
  SetName((const char*)qadm.GetName()) ;
  SetTitle((const char*)qadm.GetTitle());
}
//__________________________________________________________________
AliACORDEQADataMakerRec& AliACORDEQADataMakerRec::operator = (const AliACORDEQADataMakerRec& qadm )
{
  // Equal operator.
  this->~AliACORDEQADataMakerRec();
  new(this) AliACORDEQADataMakerRec(qadm);
  return *this;
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::EndOfDetectorCycle(AliQA::TASKINDEX_t task, TObjArray * list)
{
  //Detector specific actions at end of cycle
  // do the QA checking
  AliQAChecker::Instance()->Run(AliQA::kACORDE, task, list) ;
}

//____________________________________________________________________________
void AliACORDEQADataMakerRec::StartOfDetectorCycle()
{
  //Detector specific actions at start of cycle

}

//____________________________________________________________________________
void AliACORDEQADataMakerRec::InitRaws()
{
  // create Raw histograms in Raw subdir

TH1D *fhACORDEBitPattern[4];
fhACORDEBitPattern[0] = new TH1D("ACORDERawDataSM","ACORDE-SingleMuon",60,1,60);//AcordeSingleMuon BitPattern
fhACORDEBitPattern[1] = new TH1D("ACORDERawDataMM","ACORDE-MultiMuon",60,1,60);//AcordeMultiMuon BitPattern
fhACORDEBitPattern[2] = new TH1D("ACORDERawDataSMM","ACORDE-SingleMuonMultiplicity",60,1,60);//AcordeSingleMuon Multiplicity
fhACORDEBitPattern[3] = new TH1D("ACORDERawDataMMM","ACORDE-MultiMuonMultiplicity",60,1,60);//AcordeMultiMuon Multiplicity
for(Int_t i=0;i<4;i++)
{
	Add2RawsList(fhACORDEBitPattern[i],i,kFALSE);
}
}
//____________________________________________________________________________

void AliACORDEQADataMakerRec::InitRecPoints()
{
  // create cluster histograms in RecPoint subdir
  // Not needed for ACORDE by now !!!
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::InitESDs()
{
  //create ESDs histograms in ESDs subdir

   TH1F *    fhESDsSingle;
   TH1F *    fhESDsMulti;

   TString   name;

   name = "hESDsSingle";
   fhESDsSingle = new TH1F(name.Data(),"hESDsSingle",60,0,60);
   Add2ESDsList(fhESDsSingle,0,kFALSE);

   name = "hESDsMulti";
   fhESDsMulti = new TH1F(name.Data(),"hESDsMulti",60,0,60);
   Add2ESDsList(fhESDsMulti,1,kFALSE);
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::MakeRaws(AliRawReader* rawReader)
{
  //fills QA histos for RAW
  rawReader->Reset();
  AliACORDERawStream rawStream(rawReader);
  size_t contSingle=0;
  size_t contMulti=0;
  UInt_t dy[4];

  bool kroSingle[60],kroMulti[60];
  UInt_t tmpDy;

  for(Int_t m=0;m<60;m++) {kroSingle[m]=0;kroMulti[m]=0;}

if(rawStream.Next())
{
        dy[0]=rawStream.GetWord(0);
        dy[1]=rawStream.GetWord(1);
        dy[2]=rawStream.GetWord(2);
        dy[3]=rawStream.GetWord(3);
        tmpDy=dy[0];
        for(Int_t r=0;r<30;++r)
        {
                kroSingle[r] = tmpDy & 1;
                tmpDy>>=1;
        }
        tmpDy=dy[1];
        for(Int_t r=30;r<60;++r)
        {
                kroSingle[r] = tmpDy & 1;
                tmpDy>>=1;
        }
        tmpDy=dy[2];
        for(Int_t r=0;r<30;++r)
        {
                kroMulti[r] = tmpDy & 1;
                tmpDy>>=1;
        }
        tmpDy=dy[3];
        for(Int_t r=30;r<60;++r)
        {
                kroMulti[r] = tmpDy & 1;
                tmpDy>>=1;
        }
        contSingle=0;
	contMulti=0;
        for(Int_t r=0;r<60;++r)
        {
                if(kroSingle[r]==1)
                {
                        GetRawsData(0)->Fill(r+1);
                        contSingle=contSingle+1;
                }
		if(kroMulti[r]==1)
		{
			GetRawsData(1)->Fill(r+1);
			contMulti++;
		}

        }GetRawsData(2)->Fill(contSingle);GetRawsData(3)->Fill(contMulti);
}
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::MakeRecPoints(TTree * clustersTree)
{
  //fills QA histos for clusters
  // Not needed for ACORDE by now !!!
}
//____________________________________________________________________________
void AliACORDEQADataMakerRec::MakeESDs(AliESDEvent * esd)
{
  //fills QA histos for ESD

        AliESDACORDE * fESDACORDE= esd->GetACORDEData();
        Int_t *fACORDEMultiMuon =fESDACORDE->GetACORDEMultiMuon();
        Int_t *fACORDESingleMuon=fESDACORDE->GetACORDESingleMuon();

       for(int i=0;i<60;i++){
            if(fACORDESingleMuon[i]==1)
               GetESDsData(0) -> Fill(i);
            if(fACORDEMultiMuon[i]==1)
               GetESDsData(1) -> Fill(i);
        }

}

<|endoftext|>


<commit_before>/*
 * Accounts model item, represents an account in the contactlist tree
 * This file is based on TelepathyQt4Yell Models
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/Account>
#include <TelepathyQt4/ContactManager>

#include "accounts-model-item.h"
#include "accounts-model.h"
#include "contact-model-item.h"

struct AccountsModelItem::Private
{
    Private(const Tp::AccountPtr &account)
        : mAccount(account)
    {
    }

    void setStatus(const QString &value);
    void setStatusMessage(const QString &value);

    Tp::AccountPtr mAccount;
};

void AccountsModelItem::Private::setStatus(const QString &value)
{
    Tp::Presence presence = mAccount->currentPresence().barePresence();
    presence.setStatus(Tp::ConnectionPresenceTypeUnset, value, QString());
    mAccount->setRequestedPresence(presence);
}

void AccountsModelItem::Private::setStatusMessage(const QString &value)
{
    Tp::Presence presence = mAccount->currentPresence().barePresence();
    presence.setStatus(Tp::ConnectionPresenceTypeUnset, QString(), value);
    mAccount->setRequestedPresence(presence);
}

AccountsModelItem::AccountsModelItem(const Tp::AccountPtr &account)
    : mPriv(new Private(account))
{
    if (!mPriv->mAccount->connection().isNull()) {
        QTimer::singleShot(0, this, SLOT(onNewConnection()));
    }

    connect(mPriv->mAccount.data(),
            SIGNAL(removed()),
            SLOT(onRemoved()));
    connect(mPriv->mAccount.data(),
            SIGNAL(serviceNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(profileChanged(Tp::ProfilePtr)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(iconNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(nicknameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(normalizedNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(validityChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(stateChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(capabilitiesChanged(Tp::ConnectionCapabilities)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectsAutomaticallyPropertyChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(parametersChanged(QVariantMap)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(changingPresence(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(automaticPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(currentPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(requestedPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(onlinenessChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(avatarChanged(Tp::Avatar)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(onlinenessChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectionStatusChanged(Tp::ConnectionStatus)),
            SLOT(onStatusChanged(Tp::ConnectionStatus)));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectionChanged(Tp::ConnectionPtr)),
            SLOT(onConnectionChanged(Tp::ConnectionPtr)));
}

AccountsModelItem::~AccountsModelItem()
{
    delete mPriv;
}

QVariant AccountsModelItem::data(int role) const
{
    switch (role) {
    case AccountsModel::ItemRole:
        return QVariant::fromValue((AccountsModelItem*)this);
    case AccountsModel::IdRole:
        return mPriv->mAccount->uniqueIdentifier();
    case AccountsModel::AvatarRole:
        return QVariant(); //TODO: Return account icon
    case AccountsModel::ValidRole:
        return mPriv->mAccount->isValid();
    case AccountsModel::EnabledRole:
        return mPriv->mAccount->isEnabled();
    case AccountsModel::ConnectionManagerNameRole:
        return mPriv->mAccount->cmName();
    case AccountsModel::ProtocolNameRole:
        return mPriv->mAccount->protocolName();
    case AccountsModel::DisplayNameRole:
    case Qt::DisplayRole:
        return mPriv->mAccount->displayName();
    case AccountsModel::IconRole:
        return mPriv->mAccount->iconName();
    case AccountsModel::NicknameRole:
        return mPriv->mAccount->nickname();
    case AccountsModel::ConnectsAutomaticallyRole:
        return mPriv->mAccount->connectsAutomatically();
    case AccountsModel::ChangingPresenceRole:
        return mPriv->mAccount->isChangingPresence();
    case AccountsModel::AutomaticPresenceRole:
        return mPriv->mAccount->automaticPresence().status();
    case AccountsModel::AutomaticPresenceTypeRole:
        return mPriv->mAccount->automaticPresence().type();
    case AccountsModel::AutomaticPresenceStatusMessageRole:
        return mPriv->mAccount->automaticPresence().statusMessage();
    case AccountsModel::CurrentPresenceRole:
        return mPriv->mAccount->currentPresence().status();
    case AccountsModel::CurrentPresenceTypeRole:
        return mPriv->mAccount->currentPresence().type();
    case AccountsModel::CurrentPresenceStatusMessageRole:
        return mPriv->mAccount->currentPresence().statusMessage();
    case AccountsModel::RequestedPresenceRole:
        return mPriv->mAccount->requestedPresence().status();
    case AccountsModel::RequestedPresenceTypeRole:
        return mPriv->mAccount->requestedPresence().type();
    case AccountsModel::RequestedPresenceStatusMessageRole:
        return mPriv->mAccount->requestedPresence().statusMessage();
    case AccountsModel::ConnectionStatusRole:
        return mPriv->mAccount->connectionStatus();
    case AccountsModel::ConnectionStatusReasonRole:
        return mPriv->mAccount->connectionStatusReason();
    default:
        return QVariant();
    }
}

bool AccountsModelItem::setData(int role, const QVariant &value)
{
    switch (role) {
    case AccountsModel::EnabledRole:
        setEnabled(value.toBool());
        return true;
    case AccountsModel::RequestedPresenceRole:
        mPriv->setStatus(value.toString());
        return true;
    case AccountsModel::RequestedPresenceStatusMessageRole:
        mPriv->setStatusMessage(value.toString());
        return true;
    case AccountsModel::NicknameRole:
        setNickname(value.toString());
        return true;
    default:
        return false;
    }
}

Tp::AccountPtr AccountsModelItem::account() const
{
    return mPriv->mAccount;
}

void AccountsModelItem::setEnabled(bool value)
{
    mPriv->mAccount->setEnabled(value);
}

void AccountsModelItem::setNickname(const QString &value)
{
    mPriv->mAccount->setNickname(value);
}

void AccountsModelItem::setAutomaticPresence(int type, const QString &status, const QString &statusMessage)
{
    Tp::Presence presence;
    presence.setStatus((Tp::ConnectionPresenceType) type, status, statusMessage);
    mPriv->mAccount->setAutomaticPresence(presence);
}

void AccountsModelItem::setRequestedPresence(int type, const QString &status, const QString &statusMessage)
{
    Tp::Presence presence;
    presence.setStatus((Tp::ConnectionPresenceType) type, status, statusMessage);
    mPriv->mAccount->setRequestedPresence(presence);
}

void AccountsModelItem::onRemoved()
{
    int index = parent()->indexOf(this);
    emit childrenRemoved(parent(), index, index);
}

void AccountsModelItem::onChanged()
{
    emit changed(this);
}

void AccountsModelItem::onContactsChanged(const Tp::Contacts &addedContacts,
        const Tp::Contacts &removedContacts)
{
    foreach (const Tp::ContactPtr &contact, removedContacts) {
        for (int i = 0; i < size(); ++i) {
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item->contact() == contact) {
                emit childrenRemoved(this, i, i);
                break;
            }
        }
    }

    // get the list of contact ids in the children
    QStringList idList;
    int numElems = size();
    for (int i = 0; i < numElems; ++i) {
        ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
        if (item) {
            idList.append(item->contact()->id());
        }
    }

    QList<TreeNode *> newNodes;
    foreach (const Tp::ContactPtr &contact, addedContacts) {
        if (!idList.contains(contact->id())) {
            newNodes.append(new ContactModelItem(contact));
        }
    }
    emit childrenAdded(this, newNodes);
}

void AccountsModelItem::onStatusChanged(Tp::ConnectionStatus status)
{
    onChanged();

    emit connectionStatusChanged(mPriv->mAccount->uniqueIdentifier(), status);
}

void AccountsModelItem::onNewConnection()
{
  onConnectionChanged(mPriv->mAccount->connection());
}

void AccountsModelItem::onConnectionChanged(const Tp::ConnectionPtr &connection)
{
    onChanged();

    // if the connection is invalid or disconnected, clear the contacts list
    if (connection.isNull()
            || !connection->isValid()
            || connection->status() == Tp::ConnectionStatusDisconnected) {
        emit childrenRemoved(this, 0, size() - 1);
        return;
    }

    Tp::ContactManagerPtr manager = connection->contactManager();

    connect(manager.data(),
            SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts,
                                           Tp::Channel::GroupMemberChangeDetails)),
            SLOT(onContactsChanged(Tp::Contacts,Tp::Contacts)));

    connect(manager.data(),
            SIGNAL(stateChanged(Tp::ContactListState)),
            SLOT(onContactManagerStateChanged(Tp::ContactListState)));
    onContactManagerStateChanged(manager->state());
}

void AccountsModelItem::onContactManagerStateChanged(Tp::ContactListState state)
{
    if (state == Tp::ContactListStateSuccess) {
        clearContacts();
        addKnownContacts();
    }
}

void AccountsModelItem::clearContacts()
{
    if (!mPriv->mAccount->connection().isNull() &&
        mPriv->mAccount->connection()->isValid()) {
        Tp::ContactManagerPtr manager = mPriv->mAccount->connection()->contactManager();
        Tp::Contacts contacts = manager->allKnownContacts();

        // remove the items no longer present
        for (int i = 0; i < size(); ++i) {
            bool exists = false;
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item) {
                Tp::ContactPtr itemContact = item->contact();
                if (contacts.contains(itemContact)) {
                    exists = true;
                }
            }
            if (!exists) {
                emit childrenRemoved(this, i, i);
            }
        }
    }
}

void AccountsModelItem::addKnownContacts()
{
    // reload the known contacts if it has a connection
    QList<TreeNode *> newNodes;
    if (!mPriv->mAccount->connection().isNull() &&
        mPriv->mAccount->connection()->isValid()) {
        Tp::ContactManagerPtr manager = mPriv->mAccount->connection()->contactManager();
        Tp::Contacts contacts = manager->allKnownContacts();

        // get the list of contact ids in the children
        QStringList idList;
        int numElems = size();

        for (int i = 0; i < numElems; ++i) {
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item) {
                idList.append(item->contact()->id());
            }
        }

        // only add the contact item if it is new
        foreach (const Tp::ContactPtr &contact, contacts) {
            if (!idList.contains(contact->id())) {
                newNodes.append(new ContactModelItem(contact));
            }
        }
    }

    if (newNodes.count() > 0) {
        emit childrenAdded(this, newNodes);
    }
}
<commit_msg>Initial avatars support plus KConfig for storing the selected avatar. This will hold all other settings in the future.<commit_after>/*
 * Accounts model item, represents an account in the contactlist tree
 * This file is based on TelepathyQt4Yell Models
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/Account>
#include <TelepathyQt4/ContactManager>

#include "accounts-model-item.h"
#include "accounts-model.h"
#include "contact-model-item.h"

struct AccountsModelItem::Private
{
    Private(const Tp::AccountPtr &account)
        : mAccount(account)
    {
    }

    void setStatus(const QString &value);
    void setStatusMessage(const QString &value);

    Tp::AccountPtr mAccount;
};

void AccountsModelItem::Private::setStatus(const QString &value)
{
    Tp::Presence presence = mAccount->currentPresence().barePresence();
    presence.setStatus(Tp::ConnectionPresenceTypeUnset, value, QString());
    mAccount->setRequestedPresence(presence);
}

void AccountsModelItem::Private::setStatusMessage(const QString &value)
{
    Tp::Presence presence = mAccount->currentPresence().barePresence();
    presence.setStatus(Tp::ConnectionPresenceTypeUnset, QString(), value);
    mAccount->setRequestedPresence(presence);
}

AccountsModelItem::AccountsModelItem(const Tp::AccountPtr &account)
    : mPriv(new Private(account))
{
    if (!mPriv->mAccount->connection().isNull()) {
        QTimer::singleShot(0, this, SLOT(onNewConnection()));
    }

    connect(mPriv->mAccount.data(),
            SIGNAL(removed()),
            SLOT(onRemoved()));
    connect(mPriv->mAccount.data(),
            SIGNAL(serviceNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(profileChanged(Tp::ProfilePtr)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(iconNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(nicknameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(normalizedNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(validityChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(stateChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(capabilitiesChanged(Tp::ConnectionCapabilities)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectsAutomaticallyPropertyChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(parametersChanged(QVariantMap)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(changingPresence(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(automaticPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(currentPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(requestedPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(onlinenessChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(avatarChanged(Tp::Avatar)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(onlinenessChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectionStatusChanged(Tp::ConnectionStatus)),
            SLOT(onStatusChanged(Tp::ConnectionStatus)));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectionChanged(Tp::ConnectionPtr)),
            SLOT(onConnectionChanged(Tp::ConnectionPtr)));
}

AccountsModelItem::~AccountsModelItem()
{
    delete mPriv;
}

QVariant AccountsModelItem::data(int role) const
{
    switch (role) {
    case AccountsModel::ItemRole:
        return QVariant::fromValue((AccountsModelItem*)this);
    case AccountsModel::IdRole:
        return mPriv->mAccount->uniqueIdentifier();
    case AccountsModel::AvatarRole:
        return QVariant::fromValue(mPriv->mAccount->avatar());
    case AccountsModel::ValidRole:
        return mPriv->mAccount->isValid();
    case AccountsModel::EnabledRole:
        return mPriv->mAccount->isEnabled();
    case AccountsModel::ConnectionManagerNameRole:
        return mPriv->mAccount->cmName();
    case AccountsModel::ProtocolNameRole:
        return mPriv->mAccount->protocolName();
    case AccountsModel::DisplayNameRole:
    case Qt::DisplayRole:
        return mPriv->mAccount->displayName();
    case AccountsModel::IconRole:
        return mPriv->mAccount->iconName();
    case AccountsModel::NicknameRole:
        return mPriv->mAccount->nickname();
    case AccountsModel::ConnectsAutomaticallyRole:
        return mPriv->mAccount->connectsAutomatically();
    case AccountsModel::ChangingPresenceRole:
        return mPriv->mAccount->isChangingPresence();
    case AccountsModel::AutomaticPresenceRole:
        return mPriv->mAccount->automaticPresence().status();
    case AccountsModel::AutomaticPresenceTypeRole:
        return mPriv->mAccount->automaticPresence().type();
    case AccountsModel::AutomaticPresenceStatusMessageRole:
        return mPriv->mAccount->automaticPresence().statusMessage();
    case AccountsModel::CurrentPresenceRole:
        return mPriv->mAccount->currentPresence().status();
    case AccountsModel::CurrentPresenceTypeRole:
        return mPriv->mAccount->currentPresence().type();
    case AccountsModel::CurrentPresenceStatusMessageRole:
        return mPriv->mAccount->currentPresence().statusMessage();
    case AccountsModel::RequestedPresenceRole:
        return mPriv->mAccount->requestedPresence().status();
    case AccountsModel::RequestedPresenceTypeRole:
        return mPriv->mAccount->requestedPresence().type();
    case AccountsModel::RequestedPresenceStatusMessageRole:
        return mPriv->mAccount->requestedPresence().statusMessage();
    case AccountsModel::ConnectionStatusRole:
        return mPriv->mAccount->connectionStatus();
    case AccountsModel::ConnectionStatusReasonRole:
        return mPriv->mAccount->connectionStatusReason();
    default:
        return QVariant();
    }
}

bool AccountsModelItem::setData(int role, const QVariant &value)
{
    switch (role) {
    case AccountsModel::EnabledRole:
        setEnabled(value.toBool());
        return true;
    case AccountsModel::RequestedPresenceRole:
        mPriv->setStatus(value.toString());
        return true;
    case AccountsModel::RequestedPresenceStatusMessageRole:
        mPriv->setStatusMessage(value.toString());
        return true;
    case AccountsModel::NicknameRole:
        setNickname(value.toString());
        return true;
    case AccountsModel::AvatarRole:
        mPriv->mAccount->setAvatar(value.value<Tp::Avatar>());
        return true;
    default:
        return false;
    }
}

Tp::AccountPtr AccountsModelItem::account() const
{
    return mPriv->mAccount;
}

void AccountsModelItem::setEnabled(bool value)
{
    mPriv->mAccount->setEnabled(value);
}

void AccountsModelItem::setNickname(const QString &value)
{
    mPriv->mAccount->setNickname(value);
}

void AccountsModelItem::setAutomaticPresence(int type, const QString &status, const QString &statusMessage)
{
    Tp::Presence presence;
    presence.setStatus((Tp::ConnectionPresenceType) type, status, statusMessage);
    mPriv->mAccount->setAutomaticPresence(presence);
}

void AccountsModelItem::setRequestedPresence(int type, const QString &status, const QString &statusMessage)
{
    Tp::Presence presence;
    presence.setStatus((Tp::ConnectionPresenceType) type, status, statusMessage);
    mPriv->mAccount->setRequestedPresence(presence);
}

void AccountsModelItem::onRemoved()
{
    int index = parent()->indexOf(this);
    emit childrenRemoved(parent(), index, index);
}

void AccountsModelItem::onChanged()
{
    emit changed(this);
}

void AccountsModelItem::onContactsChanged(const Tp::Contacts &addedContacts,
        const Tp::Contacts &removedContacts)
{
    foreach (const Tp::ContactPtr &contact, removedContacts) {
        for (int i = 0; i < size(); ++i) {
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item->contact() == contact) {
                emit childrenRemoved(this, i, i);
                break;
            }
        }
    }

    // get the list of contact ids in the children
    QStringList idList;
    int numElems = size();
    for (int i = 0; i < numElems; ++i) {
        ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
        if (item) {
            idList.append(item->contact()->id());
        }
    }

    QList<TreeNode *> newNodes;
    foreach (const Tp::ContactPtr &contact, addedContacts) {
        if (!idList.contains(contact->id())) {
            newNodes.append(new ContactModelItem(contact));
        }
    }
    emit childrenAdded(this, newNodes);
}

void AccountsModelItem::onStatusChanged(Tp::ConnectionStatus status)
{
    onChanged();

    emit connectionStatusChanged(mPriv->mAccount->uniqueIdentifier(), status);
}

void AccountsModelItem::onNewConnection()
{
  onConnectionChanged(mPriv->mAccount->connection());
}

void AccountsModelItem::onConnectionChanged(const Tp::ConnectionPtr &connection)
{
    onChanged();

    // if the connection is invalid or disconnected, clear the contacts list
    if (connection.isNull()
            || !connection->isValid()
            || connection->status() == Tp::ConnectionStatusDisconnected) {
        emit childrenRemoved(this, 0, size() - 1);
        return;
    }

    Tp::ContactManagerPtr manager = connection->contactManager();

    connect(manager.data(),
            SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts,
                                           Tp::Channel::GroupMemberChangeDetails)),
            SLOT(onContactsChanged(Tp::Contacts,Tp::Contacts)));

    connect(manager.data(),
            SIGNAL(stateChanged(Tp::ContactListState)),
            SLOT(onContactManagerStateChanged(Tp::ContactListState)));
    onContactManagerStateChanged(manager->state());
}

void AccountsModelItem::onContactManagerStateChanged(Tp::ContactListState state)
{
    if (state == Tp::ContactListStateSuccess) {
        clearContacts();
        addKnownContacts();
    }
}

void AccountsModelItem::clearContacts()
{
    if (!mPriv->mAccount->connection().isNull() &&
        mPriv->mAccount->connection()->isValid()) {
        Tp::ContactManagerPtr manager = mPriv->mAccount->connection()->contactManager();
        Tp::Contacts contacts = manager->allKnownContacts();

        // remove the items no longer present
        for (int i = 0; i < size(); ++i) {
            bool exists = false;
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item) {
                Tp::ContactPtr itemContact = item->contact();
                if (contacts.contains(itemContact)) {
                    exists = true;
                }
            }
            if (!exists) {
                emit childrenRemoved(this, i, i);
            }
        }
    }
}

void AccountsModelItem::addKnownContacts()
{
    // reload the known contacts if it has a connection
    QList<TreeNode *> newNodes;
    if (!mPriv->mAccount->connection().isNull() &&
        mPriv->mAccount->connection()->isValid()) {
        Tp::ContactManagerPtr manager = mPriv->mAccount->connection()->contactManager();
        Tp::Contacts contacts = manager->allKnownContacts();

        // get the list of contact ids in the children
        QStringList idList;
        int numElems = size();

        for (int i = 0; i < numElems; ++i) {
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item) {
                idList.append(item->contact()->id());
            }
        }

        // only add the contact item if it is new
        foreach (const Tp::ContactPtr &contact, contacts) {
            if (!idList.contains(contact->id())) {
                newNodes.append(new ContactModelItem(contact));
            }
        }
    }

    if (newNodes.count() > 0) {
        emit childrenAdded(this, newNodes);
    }
}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  area_bullet.cpp                                                      */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "area_bullet.h"

#include "bullet_physics_server.h"
#include "bullet_types_converter.h"
#include "bullet_utilities.h"
#include "collision_object_bullet.h"
#include "space_bullet.h"

#include <BulletCollision/CollisionDispatch/btGhostObject.h>
#include <btBulletCollisionCommon.h>

/**
	@author AndreaCatania
*/

AreaBullet::AreaBullet() :
		RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_AREA) {
	btGhost = bulletnew(btGhostObject);
	reload_shapes();
	setupBulletCollisionObject(btGhost);
	/// Collision objects with a callback still have collision response with dynamic rigid bodies.
	/// In order to use collision objects as trigger, you have to disable the collision response.
	set_collision_enabled(false);

	for (int i = 0; i < 5; ++i) {
		call_event_res_ptr[i] = &call_event_res[i];
	}
}

AreaBullet::~AreaBullet() {
	// signal are handled by godot, so just clear without notify
	for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
		overlappingObjects[i].object->on_exit_area(this);
	}
}

void AreaBullet::dispatch_callbacks() {
	if (!isScratched) {
		return;
	}
	isScratched = false;

	// Reverse order because I've to remove EXIT objects
	for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
		OverlappingObjectData &otherObj = overlappingObjects.write[i];

		switch (otherObj.state) {
			case OVERLAP_STATE_ENTER:
				otherObj.state = OVERLAP_STATE_INSIDE;
				call_event(otherObj.object, PhysicsServer3D::AREA_BODY_ADDED);
				otherObj.object->on_enter_area(this);
				break;
			case OVERLAP_STATE_EXIT:
				call_event(otherObj.object, PhysicsServer3D::AREA_BODY_REMOVED);
				otherObj.object->on_exit_area(this);
				overlappingObjects.remove(i); // Remove after callback
				break;
			case OVERLAP_STATE_DIRTY:
			case OVERLAP_STATE_INSIDE:
				break;
		}
	}
}

void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status) {
	InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_otherObject->getType())];
	Object *areaGodoObject = ObjectDB::get_instance(event.event_callback_id);

	if (!areaGodoObject) {
		event.event_callback_id = ObjectID();
		return;
	}

	call_event_res[0] = p_status;
	call_event_res[1] = p_otherObject->get_self(); // Other body
	call_event_res[2] = p_otherObject->get_instance_id(); // instance ID
	call_event_res[3] = 0; // other_body_shape ID
	call_event_res[4] = 0; // self_shape ID

	Callable::CallError outResp;
	areaGodoObject->call(event.event_callback_method, (const Variant **)call_event_res_ptr, 5, outResp);
}

void AreaBullet::scratch() {
	if (isScratched) {
		return;
	}
	isScratched = true;
}

void AreaBullet::clear_overlaps(bool p_notify) {
	for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
		if (p_notify) {
			call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED);
		}
		overlappingObjects[i].object->on_exit_area(this);
	}
	overlappingObjects.clear();
}

void AreaBullet::remove_overlap(CollisionObjectBullet *p_object, bool p_notify) {
	for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
		if (overlappingObjects[i].object == p_object) {
			if (p_notify) {
				call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED);
			}
			overlappingObjects[i].object->on_exit_area(this);
			overlappingObjects.remove(i);
			break;
		}
	}
}

int AreaBullet::find_overlapping_object(CollisionObjectBullet *p_colObj) {
	const int size = overlappingObjects.size();
	for (int i = 0; i < size; ++i) {
		if (overlappingObjects[i].object == p_colObj) {
			return i;
		}
	}
	return -1;
}

void AreaBullet::set_monitorable(bool p_monitorable) {
	monitorable = p_monitorable;
}

bool AreaBullet::is_monitoring() const {
	return get_godot_object_flags() & GOF_IS_MONITORING_AREA;
}

void AreaBullet::main_shape_changed() {
	CRASH_COND(!get_main_shape());
	btGhost->setCollisionShape(get_main_shape());
}

void AreaBullet::do_reload_body() {
	if (space) {
		space->remove_area(this);
		space->add_area(this);
	}
}

void AreaBullet::set_space(SpaceBullet *p_space) {
	// Clear the old space if there is one
	if (space) {
		overlappingObjects.clear();
		isScratched = false;

		// Remove this object form the physics world
		space->unregister_collision_object(this);
		space->remove_area(this);
	}

	space = p_space;

	if (space) {
		space->register_collision_object(this);
		reload_body();
	}
}

void AreaBullet::on_collision_filters_change() {
	if (space) {
		space->reload_collision_filters(this);
	}
}

void AreaBullet::add_overlap(CollisionObjectBullet *p_otherObject) {
	scratch();
	overlappingObjects.push_back(OverlappingObjectData(p_otherObject, OVERLAP_STATE_ENTER));
	p_otherObject->notify_new_overlap(this);
}

void AreaBullet::put_overlap_as_exit(int p_index) {
	scratch();
	overlappingObjects.write[p_index].state = OVERLAP_STATE_EXIT;
}

void AreaBullet::put_overlap_as_inside(int p_index) {
	// This check is required to be sure this body was inside
	if (OVERLAP_STATE_DIRTY == overlappingObjects[p_index].state) {
		overlappingObjects.write[p_index].state = OVERLAP_STATE_INSIDE;
	}
}

void AreaBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) {
	switch (p_param) {
		case PhysicsServer3D::AREA_PARAM_GRAVITY:
			set_spOv_gravityMag(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
			set_spOv_gravityVec(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
			set_spOv_linearDump(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
			set_spOv_angularDump(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_PRIORITY:
			set_spOv_priority(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
			set_spOv_gravityPoint(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
			set_spOv_gravityPointDistanceScale(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
			set_spOv_gravityPointAttenuation(p_value);
			break;
		default:
			WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param));
	}
}

Variant AreaBullet::get_param(PhysicsServer3D::AreaParameter p_param) const {
	switch (p_param) {
		case PhysicsServer3D::AREA_PARAM_GRAVITY:
			return spOv_gravityMag;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
			return spOv_gravityVec;
		case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
			return spOv_linearDump;
		case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
			return spOv_angularDump;
		case PhysicsServer3D::AREA_PARAM_PRIORITY:
			return spOv_priority;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
			return spOv_gravityPoint;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
			return spOv_gravityPointDistanceScale;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
			return spOv_gravityPointAttenuation;
		default:
			WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param));
			return Variant();
	}
}

void AreaBullet::set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method) {
	InOutEventCallback &ev = eventsCallbacks[static_cast<int>(p_callbackObjectType)];
	ev.event_callback_id = p_id;
	ev.event_callback_method = p_method;

	/// Set if monitoring
	if (eventsCallbacks[0].event_callback_id.is_valid() || eventsCallbacks[1].event_callback_id.is_valid()) {
		set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA);
	} else {
		set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA));
	}
}

bool AreaBullet::has_event_callback(Type p_callbackObjectType) {
	return eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback_id.is_valid();
}

void AreaBullet::on_enter_area(AreaBullet *p_area) {
}

void AreaBullet::on_exit_area(AreaBullet *p_area) {
	CollisionObjectBullet::on_exit_area(p_area);
}
<commit_msg>Fix overlappingObjects vector crash<commit_after>/*************************************************************************/
/*  area_bullet.cpp                                                      */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "area_bullet.h"

#include "bullet_physics_server.h"
#include "bullet_types_converter.h"
#include "bullet_utilities.h"
#include "collision_object_bullet.h"
#include "space_bullet.h"

#include <BulletCollision/CollisionDispatch/btGhostObject.h>
#include <btBulletCollisionCommon.h>

/**
	@author AndreaCatania
*/

AreaBullet::AreaBullet() :
		RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_AREA) {
	btGhost = bulletnew(btGhostObject);
	reload_shapes();
	setupBulletCollisionObject(btGhost);
	/// Collision objects with a callback still have collision response with dynamic rigid bodies.
	/// In order to use collision objects as trigger, you have to disable the collision response.
	set_collision_enabled(false);

	for (int i = 0; i < 5; ++i) {
		call_event_res_ptr[i] = &call_event_res[i];
	}
}

AreaBullet::~AreaBullet() {
	// signal are handled by godot, so just clear without notify
	for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
		overlappingObjects[i].object->on_exit_area(this);
	}
}

void AreaBullet::dispatch_callbacks() {
	if (!isScratched) {
		return;
	}
	isScratched = false;

	// Reverse order because I've to remove EXIT objects
	for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
		OverlappingObjectData &otherObj = overlappingObjects.write[i];

		switch (otherObj.state) {
			case OVERLAP_STATE_ENTER:
				otherObj.state = OVERLAP_STATE_INSIDE;
				call_event(otherObj.object, PhysicsServer3D::AREA_BODY_ADDED);
				otherObj.object->on_enter_area(this);
				break;
			case OVERLAP_STATE_EXIT:
				call_event(otherObj.object, PhysicsServer3D::AREA_BODY_REMOVED);
				otherObj.object->on_exit_area(this);
				overlappingObjects.remove(i); // Remove after callback
				break;
			case OVERLAP_STATE_DIRTY:
			case OVERLAP_STATE_INSIDE:
				break;
		}
	}
}

void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status) {
	InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_otherObject->getType())];
	Object *areaGodoObject = ObjectDB::get_instance(event.event_callback_id);

	if (!areaGodoObject) {
		event.event_callback_id = ObjectID();
		return;
	}

	call_event_res[0] = p_status;
	call_event_res[1] = p_otherObject->get_self(); // Other body
	call_event_res[2] = p_otherObject->get_instance_id(); // instance ID
	call_event_res[3] = 0; // other_body_shape ID
	call_event_res[4] = 0; // self_shape ID

	Callable::CallError outResp;
	areaGodoObject->call(event.event_callback_method, (const Variant **)call_event_res_ptr, 5, outResp);
}

void AreaBullet::scratch() {
	if (isScratched) {
		return;
	}
	isScratched = true;
}

void AreaBullet::clear_overlaps(bool p_notify) {
	for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
		if (p_notify) {
			call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED);
		}
		overlappingObjects[i].object->on_exit_area(this);
	}
	overlappingObjects.clear();
}

void AreaBullet::remove_overlap(CollisionObjectBullet *p_object, bool p_notify) {
	for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
		if (overlappingObjects[i].object == p_object) {
			if (p_notify) {
				call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED);
			}
			overlappingObjects[i].object->on_exit_area(this);
			overlappingObjects.remove(i);
			break;
		}
	}
}

int AreaBullet::find_overlapping_object(CollisionObjectBullet *p_colObj) {
	const int size = overlappingObjects.size();
	for (int i = 0; i < size; ++i) {
		if (overlappingObjects[i].object == p_colObj) {
			return i;
		}
	}
	return -1;
}

void AreaBullet::set_monitorable(bool p_monitorable) {
	monitorable = p_monitorable;
}

bool AreaBullet::is_monitoring() const {
	return get_godot_object_flags() & GOF_IS_MONITORING_AREA;
}

void AreaBullet::main_shape_changed() {
	CRASH_COND(!get_main_shape());
	btGhost->setCollisionShape(get_main_shape());
}

void AreaBullet::do_reload_body() {
	if (space) {
		space->remove_area(this);
		space->add_area(this);
	}
}

void AreaBullet::set_space(SpaceBullet *p_space) {
	// Clear the old space if there is one
	if (space) {
		clear_overlaps(false);
		isScratched = false;

		// Remove this object form the physics world
		space->unregister_collision_object(this);
		space->remove_area(this);
	}

	space = p_space;

	if (space) {
		space->register_collision_object(this);
		reload_body();
	}
}

void AreaBullet::on_collision_filters_change() {
	if (space) {
		space->reload_collision_filters(this);
	}
}

void AreaBullet::add_overlap(CollisionObjectBullet *p_otherObject) {
	scratch();
	overlappingObjects.push_back(OverlappingObjectData(p_otherObject, OVERLAP_STATE_ENTER));
	p_otherObject->notify_new_overlap(this);
}

void AreaBullet::put_overlap_as_exit(int p_index) {
	scratch();
	overlappingObjects.write[p_index].state = OVERLAP_STATE_EXIT;
}

void AreaBullet::put_overlap_as_inside(int p_index) {
	// This check is required to be sure this body was inside
	if (OVERLAP_STATE_DIRTY == overlappingObjects[p_index].state) {
		overlappingObjects.write[p_index].state = OVERLAP_STATE_INSIDE;
	}
}

void AreaBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) {
	switch (p_param) {
		case PhysicsServer3D::AREA_PARAM_GRAVITY:
			set_spOv_gravityMag(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
			set_spOv_gravityVec(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
			set_spOv_linearDump(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
			set_spOv_angularDump(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_PRIORITY:
			set_spOv_priority(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
			set_spOv_gravityPoint(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
			set_spOv_gravityPointDistanceScale(p_value);
			break;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
			set_spOv_gravityPointAttenuation(p_value);
			break;
		default:
			WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param));
	}
}

Variant AreaBullet::get_param(PhysicsServer3D::AreaParameter p_param) const {
	switch (p_param) {
		case PhysicsServer3D::AREA_PARAM_GRAVITY:
			return spOv_gravityMag;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
			return spOv_gravityVec;
		case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
			return spOv_linearDump;
		case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
			return spOv_angularDump;
		case PhysicsServer3D::AREA_PARAM_PRIORITY:
			return spOv_priority;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
			return spOv_gravityPoint;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
			return spOv_gravityPointDistanceScale;
		case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
			return spOv_gravityPointAttenuation;
		default:
			WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param));
			return Variant();
	}
}

void AreaBullet::set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method) {
	InOutEventCallback &ev = eventsCallbacks[static_cast<int>(p_callbackObjectType)];
	ev.event_callback_id = p_id;
	ev.event_callback_method = p_method;

	/// Set if monitoring
	if (eventsCallbacks[0].event_callback_id.is_valid() || eventsCallbacks[1].event_callback_id.is_valid()) {
		set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA);
	} else {
		set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA));
	}
}

bool AreaBullet::has_event_callback(Type p_callbackObjectType) {
	return eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback_id.is_valid();
}

void AreaBullet::on_enter_area(AreaBullet *p_area) {
}

void AreaBullet::on_exit_area(AreaBullet *p_area) {
	CollisionObjectBullet::on_exit_area(p_area);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main() {
	string line;
	ifstream myFile("Animals.txt");
	if(myFile.is_open()) {
		while(getline(myFile, line)) {
			cout << line << "\n";
		}
		myFile.close();
	}
	else
		cout << "Unable to open file.";
	return 0;
}
<commit_msg>Delete exampleReadFiles.cpp<commit_after><|endoftext|>