<commit_before>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include <ksync/ksync_index.h>
#include "vrouter/ksync/mirror_ksync.h"
#include "vrouter/ksync/nexthop_ksync.h"
#include "vrouter/ksync/ksync_init.h"
#include <ksync/ksync_sock.h>
#include "vr_mirror.h"

MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj,
                                   const MirrorKSyncEntry *entry,
                                   uint32_t index) :
    KSyncNetlinkDBEntry(index), ksync_obj_(obj), vrf_id_(entry->vrf_id_),
    sip_(entry->sip_), sport_(entry->sport_), dip_(entry->dip_),
    dport_(entry->dport_), analyzer_name_(entry->analyzer_name_),
    mirror_flag_(entry->mirror_flag_), vni_(entry->vni_) {
}

MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj,
                                   const uint32_t vrf_id, IpAddress dip,
                                   uint16_t dport) :
    KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj), vrf_id_(vrf_id),
    dip_(dip), dport_(dport) {
}

MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj,
                                   const MirrorEntry *mirror_entry) :
    KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj),
    vrf_id_(mirror_entry->vrf_id()), sip_(*mirror_entry->GetSip()),
    sport_(mirror_entry->GetSPort()), dip_(*mirror_entry->GetDip()),
    dport_(mirror_entry->GetDPort()), nh_(NULL),
    analyzer_name_(mirror_entry->GetAnalyzerName()),
    mirror_flag_(mirror_entry->GetMirrorFlag()), vni_(mirror_entry->GetVni()) {
}

MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj,
                                   std::string &analyzer_name) :
    ksync_obj_(obj), analyzer_name_(analyzer_name) {
}

MirrorKSyncEntry::~MirrorKSyncEntry() {
}

KSyncDBObject *MirrorKSyncEntry::GetObject() {
    return ksync_obj_;
}

bool MirrorKSyncEntry::IsLess(const KSyncEntry &rhs) const {
    const MirrorKSyncEntry &entry = static_cast<const MirrorKSyncEntry &>(rhs);
    return (analyzer_name_ < entry.analyzer_name_);
}

std::string MirrorKSyncEntry::ToString() const {
    std::stringstream s;

    s << "Mirror Entry : " << dip_.to_string() << ":" << dport_;
    const VrfEntry* vrf =
        ksync_obj_->ksync()->agent()->vrf_table()->FindVrfFromId(vrf_id_);
    if (vrf) {
        s << " Vrf : " << vrf->GetName();
    }
    return s.str();
}

bool MirrorKSyncEntry::Sync(DBEntry *e) {
    bool ret = false;
    const MirrorEntry *mirror = static_cast<MirrorEntry *>(e);

    NHKSyncObject *nh_object = ksync_obj_->ksync()->nh_ksync_obj();
    if (mirror->GetNH() == NULL) {
        LOG(DEBUG, "nexthop in Mirror entry is null");
        assert(0);
    }
    NHKSyncEntry nh_entry(nh_object, mirror->GetNH());
    NHKSyncEntry *old_nh = nh();

    nh_ = nh_object->GetReference(&nh_entry);
    if (old_nh != nh()) {
        ret = true;
    }

    return ret;
}

int MirrorKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) {
    vr_mirror_req encoder;
    int encode_len;
    NHKSyncEntry *nh_entry = nh();

    encoder.set_h_op(op);
    encoder.set_mirr_index(GetIndex());
    encoder.set_mirr_rid(0);
    encoder.set_mirr_nhid(nh_entry->nh_id());
    encoder.set_mirr_vni(vni_);
    if (mirror_flag_ == MirrorEntryData::DynamicNH_With_JuniperHdr) {
        encoder.set_mirr_flags(VR_MIRROR_FLAG_DYNAMIC);
    }
    int error = 0;
    encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
    assert(error == 0);
    assert(encode_len <= buf_len);
    LOG(DEBUG, "Mirror index " << GetIndex() << " nhid "
            << nh_entry->nh_id());
    return encode_len;
}

int MirrorKSyncEntry::AddMsg(char *buf, int buf_len) {
    LOG(DEBUG, "MirrorEntry: Add");
    return Encode(sandesh_op::ADD, buf, buf_len);
}

int MirrorKSyncEntry::ChangeMsg(char *buf, int buf_len){
    return AddMsg(buf, buf_len);
}

int MirrorKSyncEntry::DeleteMsg(char *buf, int buf_len) {
    LOG(DEBUG, "MirrorEntry: Delete");
    return Encode(sandesh_op::DELETE, buf, buf_len);
}

KSyncEntry *MirrorKSyncEntry::UnresolvedReference() {
    NHKSyncEntry *nh_entry = nh();
    if (!nh_entry->IsResolved()) {
        return nh_entry;
    }
    return NULL;
}

MirrorKSyncObject::MirrorKSyncObject(KSync *ksync) :
    KSyncDBObject("KSync Mirror", kMirrorIndexCount), ksync_(ksync) {
}

MirrorKSyncObject::~MirrorKSyncObject() {
}

void MirrorKSyncObject::RegisterDBClients() {
    RegisterDb(ksync_->agent()->mirror_table());
}

KSyncEntry *MirrorKSyncObject::Alloc(const KSyncEntry *entry, uint32_t index) {
    const MirrorKSyncEntry *mirror_entry =
        static_cast<const MirrorKSyncEntry *>(entry);
    MirrorKSyncEntry *ksync = new MirrorKSyncEntry(this, mirror_entry, index);
    return static_cast<KSyncEntry *>(ksync);
}

KSyncEntry *MirrorKSyncObject::DBToKSyncEntry(const DBEntry *e) {
    const MirrorEntry *mirror_entry = static_cast<const MirrorEntry *>(e);
    MirrorKSyncEntry *ksync = new MirrorKSyncEntry(this, mirror_entry);
    return static_cast<KSyncEntry *>(ksync);
}

uint32_t MirrorKSyncObject::GetIdx(std::string analyzer_name) {
    MirrorKSyncEntry key(this, analyzer_name);
    KSyncEntry *entry = Find(&key);
    if (entry) {
        return entry->GetIndex();
    }
    return MirrorTable::kInvalidIndex;
}

void vr_mirror_req::Process(SandeshContext *context) {
    AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
    ioc->MirrorMsgHandler(this);
}
<commit_msg>Updated Mirror entry values VNI & mirror_flags to be synced to vrouter. Closes-Bug: #1608021<commit_after>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include <ksync/ksync_index.h>
#include "vrouter/ksync/mirror_ksync.h"
#include "vrouter/ksync/nexthop_ksync.h"
#include "vrouter/ksync/ksync_init.h"
#include <ksync/ksync_sock.h>
#include "vr_mirror.h"

MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj,
                                   const MirrorKSyncEntry *entry,
                                   uint32_t index) :
    KSyncNetlinkDBEntry(index), ksync_obj_(obj), vrf_id_(entry->vrf_id_),
    sip_(entry->sip_), sport_(entry->sport_), dip_(entry->dip_),
    dport_(entry->dport_), analyzer_name_(entry->analyzer_name_),
    mirror_flag_(entry->mirror_flag_), vni_(entry->vni_) {
}

MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj,
                                   const uint32_t vrf_id, IpAddress dip,
                                   uint16_t dport) :
    KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj), vrf_id_(vrf_id),
    dip_(dip), dport_(dport) {
}

MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj,
                                   const MirrorEntry *mirror_entry) :
    KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj),
    vrf_id_(mirror_entry->vrf_id()), sip_(*mirror_entry->GetSip()),
    sport_(mirror_entry->GetSPort()), dip_(*mirror_entry->GetDip()),
    dport_(mirror_entry->GetDPort()), nh_(NULL),
    analyzer_name_(mirror_entry->GetAnalyzerName()),
    mirror_flag_(mirror_entry->GetMirrorFlag()), vni_(mirror_entry->GetVni()) {
}

MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj,
                                   std::string &analyzer_name) :
    ksync_obj_(obj), analyzer_name_(analyzer_name) {
}

MirrorKSyncEntry::~MirrorKSyncEntry() {
}

KSyncDBObject *MirrorKSyncEntry::GetObject() {
    return ksync_obj_;
}

bool MirrorKSyncEntry::IsLess(const KSyncEntry &rhs) const {
    const MirrorKSyncEntry &entry = static_cast<const MirrorKSyncEntry &>(rhs);
    return (analyzer_name_ < entry.analyzer_name_);
}

std::string MirrorKSyncEntry::ToString() const {
    std::stringstream s;

    s << "Mirror Entry : " << dip_.to_string() << ":" << dport_;
    const VrfEntry* vrf =
        ksync_obj_->ksync()->agent()->vrf_table()->FindVrfFromId(vrf_id_);
    if (vrf) {
        s << " Vrf : " << vrf->GetName();
    }
    return s.str();
}

bool MirrorKSyncEntry::Sync(DBEntry *e) {
    bool ret = false;
    const MirrorEntry *mirror = static_cast<MirrorEntry *>(e);

    if (vni_ != mirror->GetVni()) {
        vni_ = mirror->GetVni();
        ret =true;
    }

    if (mirror_flag_ != mirror->GetMirrorFlag()) {
        mirror_flag_ = mirror->GetMirrorFlag();
        ret = true;
    }

    NHKSyncObject *nh_object = ksync_obj_->ksync()->nh_ksync_obj();
    if (mirror->GetNH() == NULL) {
        LOG(DEBUG, "nexthop in Mirror entry is null");
        assert(0);
    }
    NHKSyncEntry nh_entry(nh_object, mirror->GetNH());
    NHKSyncEntry *old_nh = nh();

    nh_ = nh_object->GetReference(&nh_entry);
    if (old_nh != nh()) {
        ret = true;
    }

    return ret;
}

int MirrorKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) {
    vr_mirror_req encoder;
    int encode_len;
    NHKSyncEntry *nh_entry = nh();

    encoder.set_h_op(op);
    encoder.set_mirr_index(GetIndex());
    encoder.set_mirr_rid(0);
    encoder.set_mirr_nhid(nh_entry->nh_id());
    encoder.set_mirr_vni(vni_);
    if (mirror_flag_ == MirrorEntryData::DynamicNH_With_JuniperHdr) {
        encoder.set_mirr_flags(VR_MIRROR_FLAG_DYNAMIC);
    }
    int error = 0;
    encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
    assert(error == 0);
    assert(encode_len <= buf_len);
    LOG(DEBUG, "Mirror index " << GetIndex() << " nhid "
            << nh_entry->nh_id());
    return encode_len;
}

int MirrorKSyncEntry::AddMsg(char *buf, int buf_len) {
    LOG(DEBUG, "MirrorEntry: Add");
    return Encode(sandesh_op::ADD, buf, buf_len);
}

int MirrorKSyncEntry::ChangeMsg(char *buf, int buf_len){
    return AddMsg(buf, buf_len);
}

int MirrorKSyncEntry::DeleteMsg(char *buf, int buf_len) {
    LOG(DEBUG, "MirrorEntry: Delete");
    return Encode(sandesh_op::DELETE, buf, buf_len);
}

KSyncEntry *MirrorKSyncEntry::UnresolvedReference() {
    NHKSyncEntry *nh_entry = nh();
    if (!nh_entry->IsResolved()) {
        return nh_entry;
    }
    return NULL;
}

MirrorKSyncObject::MirrorKSyncObject(KSync *ksync) :
    KSyncDBObject("KSync Mirror", kMirrorIndexCount), ksync_(ksync) {
}

MirrorKSyncObject::~MirrorKSyncObject() {
}

void MirrorKSyncObject::RegisterDBClients() {
    RegisterDb(ksync_->agent()->mirror_table());
}

KSyncEntry *MirrorKSyncObject::Alloc(const KSyncEntry *entry, uint32_t index) {
    const MirrorKSyncEntry *mirror_entry =
        static_cast<const MirrorKSyncEntry *>(entry);
    MirrorKSyncEntry *ksync = new MirrorKSyncEntry(this, mirror_entry, index);
    return static_cast<KSyncEntry *>(ksync);
}

KSyncEntry *MirrorKSyncObject::DBToKSyncEntry(const DBEntry *e) {
    const MirrorEntry *mirror_entry = static_cast<const MirrorEntry *>(e);
    MirrorKSyncEntry *ksync = new MirrorKSyncEntry(this, mirror_entry);
    return static_cast<KSyncEntry *>(ksync);
}

uint32_t MirrorKSyncObject::GetIdx(std::string analyzer_name) {
    MirrorKSyncEntry key(this, analyzer_name);
    KSyncEntry *entry = Find(&key);
    if (entry) {
        return entry->GetIndex();
    }
    return MirrorTable::kInvalidIndex;
}

void vr_mirror_req::Process(SandeshContext *context) {
    AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
    ioc->MirrorMsgHandler(this);
}
<|endoftext|>


<commit_before>#include "SkOSFile.h"

#ifdef SK_BUILD_FOR_WIN

static uint16_t* concat_to_16(const char src[], const char suffix[])
{
    size_t  i, len = strlen(src);
    size_t  len2 = 3 + (suffix ? strlen(suffix) : 0);
    uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t));

    for (i = 0; i < len; i++)
        dst[i] = src[i];

    if (i > 0 && dst[i-1] != '/')
        dst[i++] = '/';
    dst[i++] = '*';

    if (suffix)
    {
        while (*suffix)
            dst[i++] = *suffix++;
    }
    dst[i] = 0;
    SkASSERT(i + 1 <= len + len2);

    return dst;
}

SkUTF16_Str::SkUTF16_Str(const char src[])
{
    size_t  len = strlen(src);

    fStr = (uint16_t*)sk_malloc_throw((len + 1) * sizeof(uint16_t));
    for (size_t i = 0; i < len; i++)
        fStr[i] = src[i];
    fStr[i] = 0;
}

////////////////////////////////////////////////////////////////////////////

SkOSFile::Iter::Iter() : fHandle(0), fPath16(nil)
{
}

SkOSFile::Iter::Iter(const char path[], const char suffix[]) : fHandle(0), fPath16(nil)
{
    this->reset(path, suffix);
}

SkOSFile::Iter::~Iter()
{
    sk_free(fPath16);
    if (fHandle)
        ::FindClose(fHandle);
}

void SkOSFile::Iter::reset(const char path[], const char suffix[])
{
    if (fHandle)
    {
        ::FindClose(fHandle);
        fHandle = 0;
    }
    if (path == nil)
        path = "";

    sk_free(fPath16);
    fPath16 = concat_to_16(path, suffix);
}

static bool is_magic_dir(const uint16_t dir[])
{
    // return true for "." and ".."
    return dir[0] == '.' && (dir[1] == 0 || dir[1] == '.' && dir[2] == 0);
}

static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir)
{
    WIN32_FIND_DATAW    data;

    if (dataPtr == nil)
    {
        if (::FindNextFileW(handle, &data))
            dataPtr = &data;
        else
            return false;
    }

    for (;;)
    {
        if (getDir)
        {
            if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !is_magic_dir(dataPtr->cFileName))
                break;
        }
        else
        {
            if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
                break;
        }
        if (!::FindNextFileW(handle, dataPtr))
            return false;
    }
    // if we get here, we've found a file/dir
    if (name)
        name->setUTF16(dataPtr->cFileName);
    return true;
}

bool SkOSFile::Iter::next(SkString* name, bool getDir)
{
    WIN32_FIND_DATAW    data;
    WIN32_FIND_DATAW*   dataPtr = nil;

    if (fHandle == 0)   // our first time
    {
        if (fPath16 == nil || *fPath16 == 0)    // check for no path
            return false;

        fHandle = ::FindFirstFileW(fPath16, &data);
        if (fHandle != 0 && fHandle != (HANDLE)~0)
            dataPtr = &data;
    }
    return fHandle != (HANDLE)~0 && get_the_file(fHandle, name, dataPtr, getDir);
}

#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)

#if 0
OSStatus FSPathMakeRef (
   const UInt8 * path,
   FSRef * ref,
   Boolean * isDirectory
);
#endif

SkOSFile::Iter::Iter() : fDIR(0)
{
}

SkOSFile::Iter::Iter(const char path[], const char suffix[]) : fDIR(0)
{
    this->reset(path, suffix);
}

SkOSFile::Iter::~Iter()
{
    if (fDIR)
        ::closedir(fDIR);
}

void SkOSFile::Iter::reset(const char path[], const char suffix[])
{
    if (fDIR)
    {
        ::closedir(fDIR);
        fDIR = 0;
    }

    fPath.set(path);
    if (path)
    {
        fDIR = ::opendir(path);
        fSuffix.set(suffix);
    }
    else
        fSuffix.reset();
}

// returns true if suffix is empty, or if str ends with suffix
static bool issuffixfor(const SkString& suffix, const char str[])
{
    size_t  suffixLen = suffix.size();
    size_t  strLen = strlen(str);

    return  strLen >= suffixLen &&
            suffixLen == 0 ||
            memcmp(suffix.c_str(), str + strLen - suffixLen, suffixLen) == 0;
}

#include <sys/stat.h>

bool SkOSFile::Iter::next(SkString* name, bool getDir)
{
    if (fDIR)
    {
        dirent* entry;

        while ((entry = ::readdir(fDIR)) != NULL)
        {
            struct stat s;
            SkString    str(fPath);

            if (!str.endsWith("/") && !str.endsWith("\\"))
                str.append("/");
            str.append(entry->d_name);

            if (0 == stat(str.c_str(), &s))
            {
                if (getDir)
                {
                    if (s.st_mode & S_IFDIR)
                        break;
                }
                else
                {
                    if (!(s.st_mode & S_IFDIR) && issuffixfor(fSuffix, entry->d_name))
                        break;
                }
            }
        }
        if (entry)  // we broke out with a file
        {
            if (name)
                name->set(entry->d_name);
            return true;
        }
    }
    return false;
}

#endif

<commit_msg>Fix precedence error.<commit_after>#include "SkOSFile.h"

#ifdef SK_BUILD_FOR_WIN

static uint16_t* concat_to_16(const char src[], const char suffix[])
{
    size_t  i, len = strlen(src);
    size_t  len2 = 3 + (suffix ? strlen(suffix) : 0);
    uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t));

    for (i = 0; i < len; i++)
        dst[i] = src[i];

    if (i > 0 && dst[i-1] != '/')
        dst[i++] = '/';
    dst[i++] = '*';

    if (suffix)
    {
        while (*suffix)
            dst[i++] = *suffix++;
    }
    dst[i] = 0;
    SkASSERT(i + 1 <= len + len2);

    return dst;
}

SkUTF16_Str::SkUTF16_Str(const char src[])
{
    size_t  len = strlen(src);

    fStr = (uint16_t*)sk_malloc_throw((len + 1) * sizeof(uint16_t));
    for (size_t i = 0; i < len; i++)
        fStr[i] = src[i];
    fStr[i] = 0;
}

////////////////////////////////////////////////////////////////////////////

SkOSFile::Iter::Iter() : fHandle(0), fPath16(nil)
{
}

SkOSFile::Iter::Iter(const char path[], const char suffix[]) : fHandle(0), fPath16(nil)
{
    this->reset(path, suffix);
}

SkOSFile::Iter::~Iter()
{
    sk_free(fPath16);
    if (fHandle)
        ::FindClose(fHandle);
}

void SkOSFile::Iter::reset(const char path[], const char suffix[])
{
    if (fHandle)
    {
        ::FindClose(fHandle);
        fHandle = 0;
    }
    if (path == nil)
        path = "";

    sk_free(fPath16);
    fPath16 = concat_to_16(path, suffix);
}

static bool is_magic_dir(const uint16_t dir[])
{
    // return true for "." and ".."
    return dir[0] == '.' && (dir[1] == 0 || dir[1] == '.' && dir[2] == 0);
}

static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir)
{
    WIN32_FIND_DATAW    data;

    if (dataPtr == nil)
    {
        if (::FindNextFileW(handle, &data))
            dataPtr = &data;
        else
            return false;
    }

    for (;;)
    {
        if (getDir)
        {
            if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !is_magic_dir(dataPtr->cFileName))
                break;
        }
        else
        {
            if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
                break;
        }
        if (!::FindNextFileW(handle, dataPtr))
            return false;
    }
    // if we get here, we've found a file/dir
    if (name)
        name->setUTF16(dataPtr->cFileName);
    return true;
}

bool SkOSFile::Iter::next(SkString* name, bool getDir)
{
    WIN32_FIND_DATAW    data;
    WIN32_FIND_DATAW*   dataPtr = nil;

    if (fHandle == 0)   // our first time
    {
        if (fPath16 == nil || *fPath16 == 0)    // check for no path
            return false;

        fHandle = ::FindFirstFileW(fPath16, &data);
        if (fHandle != 0 && fHandle != (HANDLE)~0)
            dataPtr = &data;
    }
    return fHandle != (HANDLE)~0 && get_the_file(fHandle, name, dataPtr, getDir);
}

#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)

#if 0
OSStatus FSPathMakeRef (
   const UInt8 * path,
   FSRef * ref,
   Boolean * isDirectory
);
#endif

SkOSFile::Iter::Iter() : fDIR(0)
{
}

SkOSFile::Iter::Iter(const char path[], const char suffix[]) : fDIR(0)
{
    this->reset(path, suffix);
}

SkOSFile::Iter::~Iter()
{
    if (fDIR)
        ::closedir(fDIR);
}

void SkOSFile::Iter::reset(const char path[], const char suffix[])
{
    if (fDIR)
    {
        ::closedir(fDIR);
        fDIR = 0;
    }

    fPath.set(path);
    if (path)
    {
        fDIR = ::opendir(path);
        fSuffix.set(suffix);
    }
    else
        fSuffix.reset();
}

// returns true if suffix is empty, or if str ends with suffix
static bool issuffixfor(const SkString& suffix, const char str[])
{
    size_t  suffixLen = suffix.size();
    size_t  strLen = strlen(str);

    return  strLen >= suffixLen &&
            memcmp(suffix.c_str(), str + strLen - suffixLen, suffixLen) == 0;
}

#include <sys/stat.h>

bool SkOSFile::Iter::next(SkString* name, bool getDir)
{
    if (fDIR)
    {
        dirent* entry;

        while ((entry = ::readdir(fDIR)) != NULL)
        {
            struct stat s;
            SkString    str(fPath);

            if (!str.endsWith("/") && !str.endsWith("\\"))
                str.append("/");
            str.append(entry->d_name);

            if (0 == stat(str.c_str(), &s))
            {
                if (getDir)
                {
                    if (s.st_mode & S_IFDIR)
                        break;
                }
                else
                {
                    if (!(s.st_mode & S_IFDIR) && issuffixfor(fSuffix, entry->d_name))
                        break;
                }
            }
        }
        if (entry)  // we broke out with a file
        {
            if (name)
                name->set(entry->d_name);
            return true;
        }
    }
    return false;
}

#endif

<|endoftext|>


<commit_before>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Steinwurf ApS nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Steinwurf ApS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef SAK_OBJECT_REGISTRY_HPP
#define SAK_OBJECT_REGISTRY_HPP

#include <map>
#include <type_traits>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

#include "object_factory_impl.hpp"

namespace sak
{
    /// Type Info template for specifying the base class
    /// Template must be specialized for all classes that have a base class
	///
    /// Use the following macro to specify the base class:
    ///     SAF_DEFINE_PARENT(myClass, myBaseClass)
	/// Important: This macro must be used in the global namespace!
	/// Note that multiple inheritance is not supported.
    template<class T>
    struct sak_type_info
    {
        typedef void Base;
    };

#define SAK_DEFINE_PARENT(DERIVED_CLASS, BASE_CLASS) \
	namespace sak \
	{ \
		template<> \
		struct sak_type_info<DERIVED_CLASS> \
		{ \
			typedef BASE_CLASS Base; \
		}; \
	}

    /// Object registry used to store factories to construct objects of
    /// the registered types.
    class object_registry
    {
    private:
        /// The object_id that is used to index the registered types
        typedef size_t object_id;

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object_factory> >
            factory_map;

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<void> >
            object_map;

    public:

        /// Constructor of the factory registry
        object_registry()
        { }

        /// @return a factory stored in the registry
        template<class Factory>
        boost::shared_ptr<Factory> get_factory()
        {
            auto factory_id = get_object_id<Factory>();
            auto factory = find(m_lookup_by_factory_id, factory_id);

            assert(factory);

            typedef object_factory_impl<Factory> factory_type;

            auto factory_impl =
                boost::dynamic_pointer_cast<factory_type>(factory);

            assert(factory_impl);
            assert(factory_impl->m_factory);
            return factory_impl->m_factory;
        }

        /// Registers an object factory with the object registry
        /// Once a factory has been registered objects can be created
        template<class Factory, class Object>
        void set_factory()
        {
            auto factory_id = get_object_id<Factory>();
            auto object_id  = get_object_id<Object>();

            auto factory =
                boost::make_shared< object_factory_impl<Factory> >();

            m_lookup_by_factory_id[factory_id] = factory;
            m_lookup_by_object_id[object_id] = factory;

            // If the base class is not void,
            // then reuse the factory instance for the Base type
            typedef typename sak_type_info<Object>::Base Base;
            if (std::is_void< Base >::value == false)
                set_factory_instance< Base >(factory);
        }

		/// Registers an object factory instance with the object registry
        /// Once a factory has been registered objects can be created
        template<class Object>
        void set_factory_instance(const boost::shared_ptr<object_factory>& factory)
        {
            auto object_id  = get_object_id<Object>();

            m_lookup_by_object_id[object_id] = factory;

            // If the base class is not void,
            // then reuse the factory instance for the Base type
            typedef typename sak_type_info<Object>::Base Base;
			if (std::is_void< Base >::value == false)
                set_factory_instance< Base >(factory);
        }

        /// Registers an object factory function with the object registry
        /// Once a factory function has been registered objects can be created
        template<class Object>
        void set_factory(const boost::function<
			boost::shared_ptr<Object>(object_registry &)> & func)
        {
            auto object_id = get_object_id<Object>();

            auto factory =
                boost::make_shared< object_factory_function<Object> >(func);

            m_lookup_by_object_id[object_id] = factory;

			// If the base class is not void,
            // then reuse the factory instance for the Base type
            typedef typename sak_type_info<Object>::Base Base;
			if (std::is_void< Base >::value == false)
                set_factory_instance< Base >(factory);
        }

        /// Registers an object factory with the object registry. This methods
        /// can be used for factories with a non-standard build function.
        /// Users can call the get function and invoke the custom build function
        template<class Object>
        void set_object()
        {
            auto object_id = get_object_id<Object>();

            auto object = boost::make_shared<Object>();

            m_lookup_by_shared_object_id[object_id] = object;

			// If the base class is not void,
            // then also register the Base type
            typedef typename sak_type_info<Object>::Base Base;
			if (std::is_void< Base >::value == false)
                set_object_instance< Base >(object);
        }

		template<class Object>
        void set_object_instance(const boost::shared_ptr<Object>& object)
        {
            auto object_id = get_object_id<Object>();

            m_lookup_by_shared_object_id[object_id] = object;

			// If the base class is not void,
            // then also register the Base type
            typedef typename sak_type_info<Object>::Base Base;
			if (std::is_void< Base >::value == false)
                set_object_instance< Base >(object);
        }

        /// @return a factory stored in the registry
        template<class Object>
        boost::shared_ptr<Object> get_object()
        {
            auto object_id = get_object_id<Object>();
            auto object = find(m_lookup_by_shared_object_id, object_id);

            assert(object);
            return boost::static_pointer_cast<Object>(object);
        }

        /// Clears all registered factories
        void clear_factories()
        {
            m_lookup_by_factory_id.clear();
            m_lookup_by_object_id.clear();
        }

        /// @return an object created using the registered factories
        template<class Object>
        boost::shared_ptr<Object> build()
        {
            // Have you forgotten to register the parent class for Object?
            assert(has_object_id(m_lookup_by_object_id, get_object_id<Object>() ));

            auto factory = find(m_lookup_by_object_id, get_object_id<Object>() );

            assert(factory);

            auto obj = factory->build(*this);

            return boost::static_pointer_cast<Object>(obj);
        }

    private:

        /// Checks if an object id is registered in a specific category
        template<class Map>
        bool has_object_id(const Map &map, const object_id &id) const
        {
            return map.find(id) != map.end();
        }

        template<class Object>
        object_id get_object_id() const
        {
            return typeid(Object).hash_code();
        }

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object_factory>
            find(const factory_map &map, const object_id &id) const
        {
            assert(has_object_id(map,id));
            return map.at(id);
        }

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<void>
            find(const object_map &map, const object_id &id) const
        {
            assert(has_object_id(map,id));
            return map.at(id);
        }

    private:

        /// Map allowing a factory to be found based on an object's object id
        factory_map m_lookup_by_object_id;

        /// Map allowing a shared object to be found based on an object's object id
        object_map m_lookup_by_shared_object_id;

        /// Map allowing a factory to be found based on a factory's object id
        factory_map m_lookup_by_factory_id;

    };
}

#endif

<commit_msg>additional documentation<commit_after>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Steinwurf ApS nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Steinwurf ApS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef SAK_OBJECT_REGISTRY_HPP
#define SAK_OBJECT_REGISTRY_HPP

#include <map>
#include <type_traits>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

#include "object_factory_impl.hpp"

namespace sak
{
    /// Type Info template for specifying the base class
    /// Template must be specialized for all classes that have a base class
	///
    /// Use the following macro to specify the base class:
    ///     SAF_DEFINE_PARENT(myClass, myBaseClass)
	/// Important: This macro must be used in the global namespace!
	/// Note that multiple inheritance is not supported.
    template<class T>
    struct sak_type_info
    {
        typedef void Base;
    };

#define SAK_DEFINE_PARENT(DERIVED_CLASS, BASE_CLASS) \
	namespace sak \
	{ \
		template<> \
		struct sak_type_info<DERIVED_CLASS> \
		{ \
			typedef BASE_CLASS Base; \
		}; \
	}

    /// Object registry used to store factories to construct objects of
    /// the registered types.
    class object_registry
    {
    private:
        /// The object_id that is used to index the registered types
        typedef size_t object_id;

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object_factory> >
            factory_map;

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<void> >
            object_map;

    public:

        /// Constructor of the factory registry
        object_registry()
        { }

        /// @return a factory stored in the registry
        template<class Factory>
        boost::shared_ptr<Factory> get_factory()
        {
            auto factory_id = get_object_id<Factory>();
            auto factory = find(m_lookup_by_factory_id, factory_id);

            assert(factory);

            typedef object_factory_impl<Factory> factory_type;

            auto factory_impl =
                boost::dynamic_pointer_cast<factory_type>(factory);

            assert(factory_impl);
            assert(factory_impl->m_factory);
            return factory_impl->m_factory;
        }

        /// Registers an object factory with the object registry
        /// Once a factory has been registered, objects can be created
        template<class Factory, class Object>
        void set_factory()
        {
            auto factory_id = get_object_id<Factory>();
            auto object_id  = get_object_id<Object>();

            auto factory =
                boost::make_shared< object_factory_impl<Factory> >();

            m_lookup_by_factory_id[factory_id] = factory;
            m_lookup_by_object_id[object_id] = factory;

            // If the base class is not void,
            // then reuse the factory instance for the Base type
            typedef typename sak_type_info<Object>::Base Base;
            if (std::is_void< Base >::value == false)
                set_factory_instance< Base >(factory);
        }

		/// Registers an object factory instance with the object registry
        /// Once a factory has been registered objects can be created
        /// @param factory the factory instance to be used for the Object type
        template<class Object>
        void set_factory_instance(const boost::shared_ptr<object_factory>& factory)
        {
            auto object_id  = get_object_id<Object>();

            m_lookup_by_object_id[object_id] = factory;

            // If the base class is not void,
            // then reuse the factory instance for the Base type
            typedef typename sak_type_info<Object>::Base Base;
			if (std::is_void< Base >::value == false)
                set_factory_instance< Base >(factory);
        }

        /// Registers an object factory function with the object registry
        /// Once a factory function has been registered objects can be created
        /// @param func the factory function to be used for the Object type
        template<class Object>
        void set_factory(const boost::function<
			boost::shared_ptr<Object>(object_registry &)> & func)
        {
            auto object_id = get_object_id<Object>();

            auto factory =
                boost::make_shared< object_factory_function<Object> >(func);

            m_lookup_by_object_id[object_id] = factory;

			// If the base class is not void,
            // then reuse the factory instance for the Base type
            typedef typename sak_type_info<Object>::Base Base;
			if (std::is_void< Base >::value == false)
                set_factory_instance< Base >(factory);
        }

        /// Registers an Object type with the object registry, and creates a
        /// default instance of the Object type.
        /// This method can be used for factories with a non-standard build function.
        /// Users can call the get function and invoke the custom build function
        template<class Object>
        void set_object()
        {
            auto object_id = get_object_id<Object>();

            auto object = boost::make_shared<Object>();

            m_lookup_by_shared_object_id[object_id] = object;

			// If the base class is not void,
            // then also register the Base type
            typedef typename sak_type_info<Object>::Base Base;
			if (std::is_void< Base >::value == false)
                set_object_instance< Base >(object);
        }

		/// Explicitly registers an Object instance with the object registry
        /// without creating a default instance of the Object type.
        /// @param object the Object instance to be used for the Object type
        template<class Object>
        void set_object_instance(const boost::shared_ptr<Object>& object)
        {
            auto object_id = get_object_id<Object>();

            m_lookup_by_shared_object_id[object_id] = object;

			// If the base class is not void,
            // then also register the Base type
            typedef typename sak_type_info<Object>::Base Base;
			if (std::is_void< Base >::value == false)
                set_object_instance< Base >(object);
        }

        /// @return a factory stored in the registry
        template<class Object>
        boost::shared_ptr<Object> get_object()
        {
            auto object_id = get_object_id<Object>();
            auto object = find(m_lookup_by_shared_object_id, object_id);

            assert(object);
            return boost::static_pointer_cast<Object>(object);
        }

        /// Clears all registered factories
        void clear_factories()
        {
            m_lookup_by_factory_id.clear();
            m_lookup_by_object_id.clear();
        }

        /// Builds an Object with the registered factories
        /// @return an object created using the registered factories
        template<class Object>
        boost::shared_ptr<Object> build()
        {
            // Have you forgotten to register the parent class for Object?
            assert(has_object_id(m_lookup_by_object_id, get_object_id<Object>() ));

            auto factory = find(m_lookup_by_object_id, get_object_id<Object>() );

            assert(factory);

            auto obj = factory->build(*this);

            return boost::static_pointer_cast<Object>(obj);
        }

    private:

        /// Checks if an object id is registered in a specific category
        template<class Map>
        bool has_object_id(const Map &map, const object_id &id) const
        {
            return map.find(id) != map.end();
        }

        template<class Object>
        object_id get_object_id() const
        {
            return typeid(Object).hash_code();
        }

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object_factory>
            find(const factory_map &map, const object_id &id) const
        {
            assert(has_object_id(map,id));
            return map.at(id);
        }

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<void>
            find(const object_map &map, const object_id &id) const
        {
            assert(has_object_id(map,id));
            return map.at(id);
        }

    private:

        /// Map allowing a factory to be found based on an object's object id
        factory_map m_lookup_by_object_id;

        /// Map allowing a shared object to be found based on an object's object id
        object_map m_lookup_by_shared_object_id;

        /// Map allowing a factory to be found based on a factory's object id
        factory_map m_lookup_by_factory_id;

    };
}

#endif

<|endoftext|>


<commit_before>#include "OSGWidget.h"
#include "PickHandler.h"

#include <osg/Camera>

#include <osg/DisplaySettings>
#include <osg/Geode>
#include <osg/Material>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osg/StateSet>

#include <osgGA/EventQueue>
#include <osgGA/TrackballManipulator>

#include <osgUtil/IntersectionVisitor>
#include <osgUtil/PolytopeIntersector>

#include <osgViewer/View>
#include <osgViewer/ViewerEventHandlers>

#include <cassert>

#include <stdexcept>
#include <vector>

#include <QDebug>
#include <QKeyEvent>
#include <QWheelEvent>

namespace
{

#ifdef WITH_SELECTION_PROCESSING
QRect makeRectangle( const QPoint& first, const QPoint& second )
{
  // Relative to the first point, the second point may be in either one of the
  // four quadrants of an Euclidean coordinate system.
  //
  // We enumerate them in counter-clockwise order, starting from the lower-right
  // quadrant that corresponds to the default case:
  //
  //            |
  //       (3)  |  (4)
  //            |
  //     -------|-------
  //            |
  //       (2)  |  (1)
  //            |

  if( second.x() >= first.x() && second.y() >= first.y() )
    return QRect( first, second );
  else if( second.x() < first.x() && second.y() >= first.y() )
    return QRect( QPoint( second.x(), first.y() ), QPoint( first.x(), second.y() ) );
  else if( second.x() < first.x() && second.y() < first.y() )
    return QRect( second, first );
  else if( second.x() >= first.x() && second.y() < first.y() )
    return QRect( QPoint( first.x(), second.y() ), QPoint( second.x(), first.y() ) );

  // Should never reach that point...
  return QRect();
}
#endif

}

OSGWidget::OSGWidget( QWidget* parent,
                      const QGLWidget* shareWidget,
                      Qt::WindowFlags f )
  : QGLWidget( parent,
               shareWidget,
               f )
  , graphicsWindow_( new osgViewer::GraphicsWindowEmbedded( this->x(),
                                                            this->y(),
                                                            this->width(),
                                                            this->height() ) )
  , viewer_( new osgViewer::CompositeViewer )
  , selectionActive_( false )
  , selectionFinished_( true )
{
  osg::Sphere* sphere    = new osg::Sphere( osg::Vec3( 0.f, 0.f, 0.f ), 0.25f );
  osg::ShapeDrawable* sd = new osg::ShapeDrawable( sphere );
  sd->setColor( osg::Vec4( 1.f, 0.f, 0.f, 1.f ) );
  sd->setName( "A nice sphere" );

  osg::Geode* geode = new osg::Geode;
  geode->addDrawable( sd );

  // Set material for basic lighting and enable depth tests. Else, the sphere
  // will suffer from rendering errors.
  {
    osg::StateSet* stateSet = geode->getOrCreateStateSet();
    osg::Material* material = new osg::Material;

    material->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE );

    stateSet->setAttributeAndModes( material, osg::StateAttribute::ON );
    stateSet->setMode( GL_DEPTH_TEST, osg::StateAttribute::ON );
  }

  float aspectRatio = static_cast<float>( this->width() / 2 ) / static_cast<float>( this->height() );

  osg::Camera* camera = new osg::Camera;
  camera->setViewport( 0, 0, this->width() / 2, this->height() );
  camera->setClearColor( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) );
  camera->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f );
  camera->setGraphicsContext( graphicsWindow_ );

  osgViewer::View* view = new osgViewer::View;
  view->setCamera( camera );
  view->setSceneData( geode );
  view->addEventHandler( new osgViewer::StatsHandler );
#ifdef WITH_PICK_HANDLER
  view->addEventHandler( new PickHandler );
#endif
  view->setCameraManipulator( new osgGA::TrackballManipulator );

  osg::Camera* sideCamera = new osg::Camera;
  sideCamera->setViewport( this->width() /2, 0,
                           this->width() /2, this->height() );

  sideCamera->setClearColor( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) );
  sideCamera->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f );
  sideCamera->setGraphicsContext( graphicsWindow_ );

  osgViewer::View* sideView = new osgViewer::View;
  sideView->setCamera( sideCamera );
  sideView->setSceneData( geode );
  sideView->addEventHandler( new osgViewer::StatsHandler );
  sideView->setCameraManipulator( new osgGA::TrackballManipulator );

  viewer_->addView( view );
  viewer_->addView( sideView );
  viewer_->setThreadingModel( osgViewer::CompositeViewer::SingleThreaded );

  // This ensures that the widget will receive keyboard events. This focus
  // policy is not set by default. The default, Qt::NoFocus, will result in
  // keyboard events that are ignored.
  this->setFocusPolicy( Qt::StrongFocus );
  this->setMinimumSize( 100, 100 );

  // Ensures that the widget receives mouse move events even though no
  // mouse button has been pressed. We require this in order to let the
  // graphics window switch viewports properly.
  this->setMouseTracking( true );
}

OSGWidget::~OSGWidget()
{
}

void OSGWidget::paintEvent( QPaintEvent* /* paintEvent */ )
{
  this->makeCurrent();

  QPainter painter( this );
  painter.setRenderHint( QPainter::Antialiasing );

  this->paintGL();

#ifdef WITH_SELECTION_PROCESSING
  if( selectionActive_ && !selectionFinished_ )
  {
    painter.setPen( Qt::black );
    painter.setBrush( Qt::transparent );
    painter.drawRect( makeRectangle( selectionStart_, selectionEnd_ ) );
  }
#endif

  painter.end();

  this->swapBuffers();
  this->doneCurrent();
}

void OSGWidget::paintGL()
{
  viewer_->frame();
}

void OSGWidget::resizeGL( int width, int height )
{
  this->getEventQueue()->windowResize( this->x(), this->y(), width, height );
  graphicsWindow_->resized( this->x(), this->y(), width, height );

  this->onResize( width, height );
}

void OSGWidget::keyPressEvent( QKeyEvent* event )
{
  QString keyString   = event->text();
  const char* keyData = keyString.toLocal8Bit().data();

  if( event->key() == Qt::Key_S )
  {
#ifdef WITH_SELECTION_PROCESSING
    selectionActive_ = !selectionActive_;
#endif
  }
  else if( event->key() == Qt::Key_H )
    this->onHome();
  else
    this->getEventQueue()->keyPress( osgGA::GUIEventAdapter::KeySymbol( *keyData ) );
}

void OSGWidget::keyReleaseEvent( QKeyEvent* event )
{
  QString keyString   = event->text();
  const char* keyData = keyString.toLocal8Bit().data();

  this->getEventQueue()->keyRelease( osgGA::GUIEventAdapter::KeySymbol( *keyData ) );
}

void OSGWidget::mouseMoveEvent( QMouseEvent* event )
{
  // Note that we have to check the buttons mask in order to see whether the
  // left button has been pressed. A call to `button()` will only result in
  // `Qt::NoButton` for mouse move events.
  if( selectionActive_ && event->buttons() & Qt::LeftButton )
  {
    selectionEnd_ = event->pos();

    // Ensures that new paint events are created while the user moves the
    // mouse.
    this->update();
  }
  else
  {
    this->getEventQueue()->mouseMotion( static_cast<float>( event->x() ),
                                        static_cast<float>( event->y() ) );
  }
}

void OSGWidget::mousePressEvent( QMouseEvent* event )
{
  // Selection processing
  if( selectionActive_ && event->button() == Qt::LeftButton )
  {
    selectionStart_    = event->pos();
    selectionEnd_      = selectionStart_; // Deletes the old selection
    selectionFinished_ = false;           // As long as this is set, the rectangle will be drawn
  }

  // Normal processing
  else
  {
    // 1 = left mouse button
    // 2 = middle mouse button
    // 3 = right mouse button

    unsigned int button = 0;

    switch( event->button() )
    {
    case Qt::LeftButton:
      button = 1;
      break;

    case Qt::MiddleButton:
      button = 2;
      break;

    case Qt::RightButton:
      button = 3;
      break;

    default:
      break;
    }

    this->getEventQueue()->mouseButtonPress( static_cast<float>( event->x() ),
                                             static_cast<float>( event->y() ),
                                             button );
    }
}

void OSGWidget::mouseReleaseEvent(QMouseEvent* event)
{
  // Selection processing: Store end position and obtain selected objects
  // through polytope intersection.
  if( selectionActive_ && event->button() == Qt::LeftButton )
  {
    selectionEnd_      = event->pos();
    selectionFinished_ = true; // Will force the painter to stop drawing the
                               // selection rectangle

    this->processSelection();
  }

  // Normal processing
  else
  {
    // 1 = left mouse button
    // 2 = middle mouse button
    // 3 = right mouse button

    unsigned int button = 0;

    switch( event->button() )
    {
    case Qt::LeftButton:
      button = 1;
      break;

    case Qt::MiddleButton:
      button = 2;
      break;

    case Qt::RightButton:
      button = 3;
      break;

    default:
      break;
    }

    this->getEventQueue()->mouseButtonRelease( static_cast<float>( event->x() ),
                                               static_cast<float>( event->y() ),
                                               button );
  }
}

void OSGWidget::wheelEvent( QWheelEvent* event )
{
  // Ignore wheel events as long as the selection is active.
  if( selectionActive_ )
    return;

  event->accept();
  int delta = event->delta();

  osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ?   osgGA::GUIEventAdapter::SCROLL_UP
                                                               : osgGA::GUIEventAdapter::SCROLL_DOWN;

  this->getEventQueue()->mouseScroll( motion );
}

bool OSGWidget::event( QEvent* event )
{
  bool handled = QGLWidget::event( event );

  // This ensures that the OSG widget is always going to be repainted after the
  // user performed some interaction. Doing this in the event handler ensures
  // that we don't forget about some event and prevents duplicate code.
  switch( event->type() )
  {
  case QEvent::KeyPress:
  case QEvent::KeyRelease:
  case QEvent::MouseButtonDblClick:
  case QEvent::MouseButtonPress:
  case QEvent::MouseButtonRelease:
  case QEvent::MouseMove:
  case QEvent::Wheel:
    this->update();
    break;

  default:
    break;
  }

  return( handled );
}

void OSGWidget::onHome()
{
  osgViewer::ViewerBase::Views views;
  viewer_->getViews( views );

  for( std::size_t i = 0; i < views.size(); i++ )
  {
    osgViewer::View* view = views.at(i);
    view->home();
  }
}

void OSGWidget::onResize( int width, int height )
{
  std::vector<osg::Camera*> cameras;
  viewer_->getCameras( cameras );

  assert( cameras.size() == 2 );

  cameras[0]->setViewport( 0, 0, this->width() / 2, this->height() );
  cameras[1]->setViewport( this->width() / 2, 0, this->width() / 2, this->height() );
}

osgGA::EventQueue* OSGWidget::getEventQueue() const
{
  osgGA::EventQueue* eventQueue = graphicsWindow_->getEventQueue();

  if( eventQueue )
    return( eventQueue );
  else
    throw( std::runtime_error( "Unable to obtain valid event queue") );
}

void OSGWidget::processSelection()
{
#ifdef WITH_SELECTION_PROCESSING
  QRect selectionRectangle = makeRectangle( selectionStart_, selectionEnd_ );
  int widgetHeight         = this->height();

  double xMin = selectionRectangle.left();
  double xMax = selectionRectangle.right();
  double yMin = widgetHeight - selectionRectangle.bottom();
  double yMax = widgetHeight - selectionRectangle.top();

  osgUtil::PolytopeIntersector* polytopeIntersector
      = new osgUtil::PolytopeIntersector( osgUtil::PolytopeIntersector::WINDOW,
                                          xMin, yMin,
                                          xMax, yMax );

  // This limits the amount of intersections that are reported by the
  // polytope intersector. Using this setting, a single drawable will
  // appear at most once while calculating intersections. This is the
  // preferred and expected behaviour.
  polytopeIntersector->setIntersectionLimit( osgUtil::Intersector::LIMIT_ONE_PER_DRAWABLE );

  osgUtil::IntersectionVisitor iv( polytopeIntersector );

  for( unsigned int viewIndex = 0; viewIndex < viewer_->getNumViews(); viewIndex++ )
  {
    osgViewer::View* view = viewer_->getView( viewIndex );

    if( !view )
      throw std::runtime_error( "Unable to obtain valid view for selection processing" );

    osg::Camera* camera = view->getCamera();

    if( !camera )
      throw std::runtime_error( "Unable to obtain valid camera for selection processing" );

    camera->accept( iv );

    if( !polytopeIntersector->containsIntersections() )
      continue;

    auto intersections = polytopeIntersector->getIntersections();

    for( auto&& intersection : intersections )
      qDebug() << "Selected a drawable:" << QString::fromStdString( intersection.drawable->getName() );
  }
#endif
}
<commit_msg>Disable throwing behaviour for trackball manipulator<commit_after>#include "OSGWidget.h"
#include "PickHandler.h"

#include <osg/Camera>

#include <osg/DisplaySettings>
#include <osg/Geode>
#include <osg/Material>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osg/StateSet>

#include <osgGA/EventQueue>
#include <osgGA/TrackballManipulator>

#include <osgUtil/IntersectionVisitor>
#include <osgUtil/PolytopeIntersector>

#include <osgViewer/View>
#include <osgViewer/ViewerEventHandlers>

#include <cassert>

#include <stdexcept>
#include <vector>

#include <QDebug>
#include <QKeyEvent>
#include <QWheelEvent>

namespace
{

#ifdef WITH_SELECTION_PROCESSING
QRect makeRectangle( const QPoint& first, const QPoint& second )
{
  // Relative to the first point, the second point may be in either one of the
  // four quadrants of an Euclidean coordinate system.
  //
  // We enumerate them in counter-clockwise order, starting from the lower-right
  // quadrant that corresponds to the default case:
  //
  //            |
  //       (3)  |  (4)
  //            |
  //     -------|-------
  //            |
  //       (2)  |  (1)
  //            |

  if( second.x() >= first.x() && second.y() >= first.y() )
    return QRect( first, second );
  else if( second.x() < first.x() && second.y() >= first.y() )
    return QRect( QPoint( second.x(), first.y() ), QPoint( first.x(), second.y() ) );
  else if( second.x() < first.x() && second.y() < first.y() )
    return QRect( second, first );
  else if( second.x() >= first.x() && second.y() < first.y() )
    return QRect( QPoint( first.x(), second.y() ), QPoint( second.x(), first.y() ) );

  // Should never reach that point...
  return QRect();
}
#endif

}

OSGWidget::OSGWidget( QWidget* parent,
                      const QGLWidget* shareWidget,
                      Qt::WindowFlags f )
  : QGLWidget( parent,
               shareWidget,
               f )
  , graphicsWindow_( new osgViewer::GraphicsWindowEmbedded( this->x(),
                                                            this->y(),
                                                            this->width(),
                                                            this->height() ) )
  , viewer_( new osgViewer::CompositeViewer )
  , selectionActive_( false )
  , selectionFinished_( true )
{
  osg::Sphere* sphere    = new osg::Sphere( osg::Vec3( 0.f, 0.f, 0.f ), 0.25f );
  osg::ShapeDrawable* sd = new osg::ShapeDrawable( sphere );
  sd->setColor( osg::Vec4( 1.f, 0.f, 0.f, 1.f ) );
  sd->setName( "A nice sphere" );

  osg::Geode* geode = new osg::Geode;
  geode->addDrawable( sd );

  // Set material for basic lighting and enable depth tests. Else, the sphere
  // will suffer from rendering errors.
  {
    osg::StateSet* stateSet = geode->getOrCreateStateSet();
    osg::Material* material = new osg::Material;

    material->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE );

    stateSet->setAttributeAndModes( material, osg::StateAttribute::ON );
    stateSet->setMode( GL_DEPTH_TEST, osg::StateAttribute::ON );
  }

  float aspectRatio = static_cast<float>( this->width() / 2 ) / static_cast<float>( this->height() );

  osg::Camera* camera = new osg::Camera;
  camera->setViewport( 0, 0, this->width() / 2, this->height() );
  camera->setClearColor( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) );
  camera->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f );
  camera->setGraphicsContext( graphicsWindow_ );

  osgViewer::View* view = new osgViewer::View;
  view->setCamera( camera );
  view->setSceneData( geode );
  view->addEventHandler( new osgViewer::StatsHandler );
#ifdef WITH_PICK_HANDLER
  view->addEventHandler( new PickHandler );
#endif

  osgGA::TrackballManipulator* manipulator = new osgGA::TrackballManipulator;
  manipulator->setAllowThrow( false );

  view->setCameraManipulator( manipulator );

  osg::Camera* sideCamera = new osg::Camera;
  sideCamera->setViewport( this->width() /2, 0,
                           this->width() /2, this->height() );

  sideCamera->setClearColor( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) );
  sideCamera->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f );
  sideCamera->setGraphicsContext( graphicsWindow_ );

  osgViewer::View* sideView = new osgViewer::View;
  sideView->setCamera( sideCamera );
  sideView->setSceneData( geode );
  sideView->addEventHandler( new osgViewer::StatsHandler );
  sideView->setCameraManipulator( new osgGA::TrackballManipulator );

  viewer_->addView( view );
  viewer_->addView( sideView );
  viewer_->setThreadingModel( osgViewer::CompositeViewer::SingleThreaded );

  // This ensures that the widget will receive keyboard events. This focus
  // policy is not set by default. The default, Qt::NoFocus, will result in
  // keyboard events that are ignored.
  this->setFocusPolicy( Qt::StrongFocus );
  this->setMinimumSize( 100, 100 );

  // Ensures that the widget receives mouse move events even though no
  // mouse button has been pressed. We require this in order to let the
  // graphics window switch viewports properly.
  this->setMouseTracking( true );
}

OSGWidget::~OSGWidget()
{
}

void OSGWidget::paintEvent( QPaintEvent* /* paintEvent */ )
{
  this->makeCurrent();

  QPainter painter( this );
  painter.setRenderHint( QPainter::Antialiasing );

  this->paintGL();

#ifdef WITH_SELECTION_PROCESSING
  if( selectionActive_ && !selectionFinished_ )
  {
    painter.setPen( Qt::black );
    painter.setBrush( Qt::transparent );
    painter.drawRect( makeRectangle( selectionStart_, selectionEnd_ ) );
  }
#endif

  painter.end();

  this->swapBuffers();
  this->doneCurrent();
}

void OSGWidget::paintGL()
{
  viewer_->frame();
}

void OSGWidget::resizeGL( int width, int height )
{
  this->getEventQueue()->windowResize( this->x(), this->y(), width, height );
  graphicsWindow_->resized( this->x(), this->y(), width, height );

  this->onResize( width, height );
}

void OSGWidget::keyPressEvent( QKeyEvent* event )
{
  QString keyString   = event->text();
  const char* keyData = keyString.toLocal8Bit().data();

  if( event->key() == Qt::Key_S )
  {
#ifdef WITH_SELECTION_PROCESSING
    selectionActive_ = !selectionActive_;
#endif
  }
  else if( event->key() == Qt::Key_H )
    this->onHome();
  else
    this->getEventQueue()->keyPress( osgGA::GUIEventAdapter::KeySymbol( *keyData ) );
}

void OSGWidget::keyReleaseEvent( QKeyEvent* event )
{
  QString keyString   = event->text();
  const char* keyData = keyString.toLocal8Bit().data();

  this->getEventQueue()->keyRelease( osgGA::GUIEventAdapter::KeySymbol( *keyData ) );
}

void OSGWidget::mouseMoveEvent( QMouseEvent* event )
{
  // Note that we have to check the buttons mask in order to see whether the
  // left button has been pressed. A call to `button()` will only result in
  // `Qt::NoButton` for mouse move events.
  if( selectionActive_ && event->buttons() & Qt::LeftButton )
  {
    selectionEnd_ = event->pos();

    // Ensures that new paint events are created while the user moves the
    // mouse.
    this->update();
  }
  else
  {
    this->getEventQueue()->mouseMotion( static_cast<float>( event->x() ),
                                        static_cast<float>( event->y() ) );
  }
}

void OSGWidget::mousePressEvent( QMouseEvent* event )
{
  // Selection processing
  if( selectionActive_ && event->button() == Qt::LeftButton )
  {
    selectionStart_    = event->pos();
    selectionEnd_      = selectionStart_; // Deletes the old selection
    selectionFinished_ = false;           // As long as this is set, the rectangle will be drawn
  }

  // Normal processing
  else
  {
    // 1 = left mouse button
    // 2 = middle mouse button
    // 3 = right mouse button

    unsigned int button = 0;

    switch( event->button() )
    {
    case Qt::LeftButton:
      button = 1;
      break;

    case Qt::MiddleButton:
      button = 2;
      break;

    case Qt::RightButton:
      button = 3;
      break;

    default:
      break;
    }

    this->getEventQueue()->mouseButtonPress( static_cast<float>( event->x() ),
                                             static_cast<float>( event->y() ),
                                             button );
    }
}

void OSGWidget::mouseReleaseEvent(QMouseEvent* event)
{
  // Selection processing: Store end position and obtain selected objects
  // through polytope intersection.
  if( selectionActive_ && event->button() == Qt::LeftButton )
  {
    selectionEnd_      = event->pos();
    selectionFinished_ = true; // Will force the painter to stop drawing the
                               // selection rectangle

    this->processSelection();
  }

  // Normal processing
  else
  {
    // 1 = left mouse button
    // 2 = middle mouse button
    // 3 = right mouse button

    unsigned int button = 0;

    switch( event->button() )
    {
    case Qt::LeftButton:
      button = 1;
      break;

    case Qt::MiddleButton:
      button = 2;
      break;

    case Qt::RightButton:
      button = 3;
      break;

    default:
      break;
    }

    this->getEventQueue()->mouseButtonRelease( static_cast<float>( event->x() ),
                                               static_cast<float>( event->y() ),
                                               button );
  }
}

void OSGWidget::wheelEvent( QWheelEvent* event )
{
  // Ignore wheel events as long as the selection is active.
  if( selectionActive_ )
    return;

  event->accept();
  int delta = event->delta();

  osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ?   osgGA::GUIEventAdapter::SCROLL_UP
                                                               : osgGA::GUIEventAdapter::SCROLL_DOWN;

  this->getEventQueue()->mouseScroll( motion );
}

bool OSGWidget::event( QEvent* event )
{
  bool handled = QGLWidget::event( event );

  // This ensures that the OSG widget is always going to be repainted after the
  // user performed some interaction. Doing this in the event handler ensures
  // that we don't forget about some event and prevents duplicate code.
  switch( event->type() )
  {
  case QEvent::KeyPress:
  case QEvent::KeyRelease:
  case QEvent::MouseButtonDblClick:
  case QEvent::MouseButtonPress:
  case QEvent::MouseButtonRelease:
  case QEvent::MouseMove:
  case QEvent::Wheel:
    this->update();
    break;

  default:
    break;
  }

  return( handled );
}

void OSGWidget::onHome()
{
  osgViewer::ViewerBase::Views views;
  viewer_->getViews( views );

  for( std::size_t i = 0; i < views.size(); i++ )
  {
    osgViewer::View* view = views.at(i);
    view->home();
  }
}

void OSGWidget::onResize( int width, int height )
{
  std::vector<osg::Camera*> cameras;
  viewer_->getCameras( cameras );

  assert( cameras.size() == 2 );

  cameras[0]->setViewport( 0, 0, this->width() / 2, this->height() );
  cameras[1]->setViewport( this->width() / 2, 0, this->width() / 2, this->height() );
}

osgGA::EventQueue* OSGWidget::getEventQueue() const
{
  osgGA::EventQueue* eventQueue = graphicsWindow_->getEventQueue();

  if( eventQueue )
    return( eventQueue );
  else
    throw( std::runtime_error( "Unable to obtain valid event queue") );
}

void OSGWidget::processSelection()
{
#ifdef WITH_SELECTION_PROCESSING
  QRect selectionRectangle = makeRectangle( selectionStart_, selectionEnd_ );
  int widgetHeight         = this->height();

  double xMin = selectionRectangle.left();
  double xMax = selectionRectangle.right();
  double yMin = widgetHeight - selectionRectangle.bottom();
  double yMax = widgetHeight - selectionRectangle.top();

  osgUtil::PolytopeIntersector* polytopeIntersector
      = new osgUtil::PolytopeIntersector( osgUtil::PolytopeIntersector::WINDOW,
                                          xMin, yMin,
                                          xMax, yMax );

  // This limits the amount of intersections that are reported by the
  // polytope intersector. Using this setting, a single drawable will
  // appear at most once while calculating intersections. This is the
  // preferred and expected behaviour.
  polytopeIntersector->setIntersectionLimit( osgUtil::Intersector::LIMIT_ONE_PER_DRAWABLE );

  osgUtil::IntersectionVisitor iv( polytopeIntersector );

  for( unsigned int viewIndex = 0; viewIndex < viewer_->getNumViews(); viewIndex++ )
  {
    osgViewer::View* view = viewer_->getView( viewIndex );

    if( !view )
      throw std::runtime_error( "Unable to obtain valid view for selection processing" );

    osg::Camera* camera = view->getCamera();

    if( !camera )
      throw std::runtime_error( "Unable to obtain valid camera for selection processing" );

    camera->accept( iv );

    if( !polytopeIntersector->containsIntersections() )
      continue;

    auto intersections = polytopeIntersector->getIntersections();

    for( auto&& intersection : intersections )
      qDebug() << "Selected a drawable:" << QString::fromStdString( intersection.drawable->getName() );
  }
#endif
}
<|endoftext|>


<commit_before>/*
 * PersistentIdentity.cpp
 *
 *  Created on: 21 Aug 2014
 *      Author: JAragon
 */

#include "../include/MixpanelPersistentIdentity.hpp"

#include "../include/MixpanelConstants.hpp"

#include <bb/device/HardwareInfo>
#include <bb/ApplicationInfo>
#include <bb/platform/PlatformInfo>

class MixpanelPersistentIdentityPrivate : public QSharedData
{
public:
    QString token;
    QString eventDistinctId;
    QString peopleDistinctId;
    QVariantMap referrerProperties;
    QVariantMap superPropertiesCache;
};

/// Creates a PersistentIdentity object.

MixpanelPersistentIdentity::MixpanelPersistentIdentity()
    : d(new MixpanelPersistentIdentityPrivate())
{

}

/// Creates a copy of \a other.

MixpanelPersistentIdentity::MixpanelPersistentIdentity(const MixpanelPersistentIdentity& other)
    : d(other.d)
{

}

/// Destructor, destroys the MixpanelPersistentIdentity object.
///

MixpanelPersistentIdentity::~MixpanelPersistentIdentity()
{

}

/// Assigns \a other to this PersistentIdentity

MixpanelPersistentIdentity& MixpanelPersistentIdentity::operator=(const MixpanelPersistentIdentity &other)
{
    d = other.d;
    return *this;
}

/// Sets the Mixpanel token.
///
/// \param token Token of the Mixpanel account
///

void MixpanelPersistentIdentity::setToken(const QString& token)
{
    d->token = token;
}

/// Sets the distinct id for the events.
///
/// \param token distinct id to use on the events
///

void MixpanelPersistentIdentity::setEventDistinctId(const QString& distinctId)
{
    d->eventDistinctId = distinctId;
}

/// Sets the distinct id for the profile updates.
///
/// \param token distinct id to use on the profile actions
///

void MixpanelPersistentIdentity::setPeopleDisctinctId(const QString& distinctId)
{
    if (!distinctId.isEmpty())
        d->peopleDistinctId = distinctId;

    saveDistinctPeopleId();
}

/// Returns the Mixpanel account token.
///
/// \return token
///

QString MixpanelPersistentIdentity::token() const
{
    return d->token;
}

/// Returns the distinct id used for the events.
///
/// \return event distinct id
///

QString MixpanelPersistentIdentity::eventDistinctId() const
{
    return d->eventDistinctId;
}

/// Returns the distinct id used for the profile.
///
/// \return profile distinct id
///

QString MixpanelPersistentIdentity::peopleDistinctId() const
{
    return d->peopleDistinctId;
}

/// Returns the referrer properties.
///
/// \return a QVariantMap containing the referrer properties
///

QVariantMap MixpanelPersistentIdentity::referrerProperties() const
{
    return d->referrerProperties;
}

/// Returns the event super properties.
///
/// \return a QVariantMap containing the event super properties
///

QVariantMap MixpanelPersistentIdentity::eventSuperProperties() const
{
    return d->superPropertiesCache;
}

///
/// Register properties that will be sent with every subsequent call to track events.
/// SuperProperties are a collection of properties that will be sent with every event to Mixpanel,
/// and persist beyond the lifetime of your application.
///
/// Setting a superProperty with registerSuperProperties will store a new superProperty,
/// possibly overwriting any existing superProperty with the same name (to set a
/// superProperty only if it is currently unset, use registerSuperPropertiesOnce(QVariantMap)
///
/// \note SuperProperties will persist even if your application is taken completely out of memory.
/// to remove a superProperty, call unregisterSuperProperty(QString) or clearSuperProperties()
///
/// \param superProperties    A QVariantMap containing super properties to register
///

void MixpanelPersistentIdentity::registerSuperProperties(const QVariantMap& superProperties)
{
    Q_FOREACH(QString propertyName, superProperties.keys())
    {
        if (!d->superPropertiesCache.contains(propertyName))
        {
            d->superPropertiesCache.insert(propertyName, superProperties.value(propertyName));
        } else {
            d->superPropertiesCache[propertyName] = superProperties.value(propertyName);
        }
    }

    saveSuperProperties();
}

///
/// Register super properties for events, only if no other super property with the
/// same names has already been registered.
///
/// \note Calling registerSuperPropertiesOnce will never overwrite existing properties.
///
/// \param superProperties A QVariantMap containing the super properties to register.
///

void MixpanelPersistentIdentity::registerSuperPropertiesOnce(const QVariantMap& superProperties)
{
    Q_FOREACH(QString propertyName, superProperties.keys())
    {
        if (!d->superPropertiesCache.contains(propertyName))
        {
            d->superPropertiesCache.insert(propertyName, superProperties.value(propertyName));
        }
    }

    saveSuperProperties();
}

///
/// Remove a single superProperty, so that it will not be sent with future calls to track events.
///
/// \note If there is a superProperty registered with the given name, it will be permanently
/// removed from the existing superProperties.
/// To clear all superProperties, use clearSuperProperties()
///
/// \param superPropertyName name of the property to unregister
///

void MixpanelPersistentIdentity::unregisterSuperProperty(const QString& superPropertyName)
{
    if (d->superPropertiesCache.contains(superPropertyName))
    {
        d->superPropertiesCache.remove(superPropertyName);
        saveSuperProperties();
    }
}

///
/// Erase all currently registered superProperties.
///
/// /note Future tracking calls to Mixpanel (even those already queued up but not
/// yet sent to Mixpanel servers) will not be associated with the superProperties registered
/// before this call was made.
///
/// /note To remove a single superProperty, use unregisterSuperProperty(QString)
///
///

void MixpanelPersistentIdentity::clearSuperProperties()
{
    QSettings settings(g_organizationName);
    settings.remove(g_superPropertiesKey);

    d->superPropertiesCache.clear();
}

/// Read the device identity and stores it into the referrerProperties.
/// It will set the event or people distinct id as the BB PIN if they haven't been set.
///

void MixpanelPersistentIdentity::readIdentities()
{
    bb::device::HardwareInfo hardwareInfo;
    bb::ApplicationInfo appInfo;
    bb::platform::PlatformInfo platformInfo;

    d->referrerProperties.insert("$os", "BB10");
    d->referrerProperties.insert("BB10 OS version", platformInfo.osVersion());
    d->referrerProperties.insert("App version", appInfo.version());
    d->referrerProperties.insert("Device name", hardwareInfo.deviceName());
    d->referrerProperties.insert("Model", hardwareInfo.modelName());
    d->referrerProperties.insert("PIN", hardwareInfo.pin());

    if (d->eventDistinctId.isEmpty())
        setEventDistinctId(hardwareInfo.pin());

    if (d->peopleDistinctId.isEmpty())
        setPeopleDisctinctId(hardwareInfo.pin());

}

///
/// Loads all the persistent data previously saved.
///

void MixpanelPersistentIdentity::loadPersistentData()
{
    QSettings settings(g_organizationName);
    d->superPropertiesCache = settings.value(g_superPropertiesKey, QVariantMap()).toMap();

    d->peopleDistinctId = settings.value(g_peopleDistinctIdKey, QString()).toString();
}

///
/// Save all the super properties registered to make them persistent.
///

void MixpanelPersistentIdentity::saveSuperProperties()
{
    QSettings settings(g_organizationName);
    settings.setValue(g_superPropertiesKey, d->superPropertiesCache);
}

///
/// Save the distinct people id to make it persistent.
///

void MixpanelPersistentIdentity::saveDistinctPeopleId()
{
    QSettings settings(g_organizationName);
    settings.setValue(g_peopleDistinctIdKey, d->peopleDistinctId);
}

<commit_msg>Default event properties updated to match Android library.<commit_after>/*
 * PersistentIdentity.cpp
 *
 *  Created on: 21 Aug 2014
 *      Author: JAragon
 */

#include "../include/MixpanelPersistentIdentity.hpp"

#include "../include/MixpanelConstants.hpp"

#include <bb/device/HardwareInfo>
#include <bb/ApplicationInfo>
#include <bb/platform/PlatformInfo>

class MixpanelPersistentIdentityPrivate : public QSharedData
{
public:
    QString token;
    QString eventDistinctId;
    QString peopleDistinctId;
    QVariantMap referrerProperties;
    QVariantMap superPropertiesCache;
};

/// Creates a PersistentIdentity object.

MixpanelPersistentIdentity::MixpanelPersistentIdentity()
    : d(new MixpanelPersistentIdentityPrivate())
{

}

/// Creates a copy of \a other.

MixpanelPersistentIdentity::MixpanelPersistentIdentity(const MixpanelPersistentIdentity& other)
    : d(other.d)
{

}

/// Destructor, destroys the MixpanelPersistentIdentity object.
///

MixpanelPersistentIdentity::~MixpanelPersistentIdentity()
{

}

/// Assigns \a other to this PersistentIdentity

MixpanelPersistentIdentity& MixpanelPersistentIdentity::operator=(const MixpanelPersistentIdentity &other)
{
    d = other.d;
    return *this;
}

/// Sets the Mixpanel token.
///
/// \param token Token of the Mixpanel account
///

void MixpanelPersistentIdentity::setToken(const QString& token)
{
    d->token = token;
}

/// Sets the distinct id for the events.
///
/// \param token distinct id to use on the events
///

void MixpanelPersistentIdentity::setEventDistinctId(const QString& distinctId)
{
    d->eventDistinctId = distinctId;
}

/// Sets the distinct id for the profile updates.
///
/// \param token distinct id to use on the profile actions
///

void MixpanelPersistentIdentity::setPeopleDisctinctId(const QString& distinctId)
{
    if (!distinctId.isEmpty())
        d->peopleDistinctId = distinctId;

    saveDistinctPeopleId();
}

/// Returns the Mixpanel account token.
///
/// \return token
///

QString MixpanelPersistentIdentity::token() const
{
    return d->token;
}

/// Returns the distinct id used for the events.
///
/// \return event distinct id
///

QString MixpanelPersistentIdentity::eventDistinctId() const
{
    return d->eventDistinctId;
}

/// Returns the distinct id used for the profile.
///
/// \return profile distinct id
///

QString MixpanelPersistentIdentity::peopleDistinctId() const
{
    return d->peopleDistinctId;
}

/// Returns the referrer properties.
///
/// \return a QVariantMap containing the referrer properties
///

QVariantMap MixpanelPersistentIdentity::referrerProperties() const
{
    return d->referrerProperties;
}

/// Returns the event super properties.
///
/// \return a QVariantMap containing the event super properties
///

QVariantMap MixpanelPersistentIdentity::eventSuperProperties() const
{
    return d->superPropertiesCache;
}

///
/// Register properties that will be sent with every subsequent call to track events.
/// SuperProperties are a collection of properties that will be sent with every event to Mixpanel,
/// and persist beyond the lifetime of your application.
///
/// Setting a superProperty with registerSuperProperties will store a new superProperty,
/// possibly overwriting any existing superProperty with the same name (to set a
/// superProperty only if it is currently unset, use registerSuperPropertiesOnce(QVariantMap)
///
/// \note SuperProperties will persist even if your application is taken completely out of memory.
/// to remove a superProperty, call unregisterSuperProperty(QString) or clearSuperProperties()
///
/// \param superProperties    A QVariantMap containing super properties to register
///

void MixpanelPersistentIdentity::registerSuperProperties(const QVariantMap& superProperties)
{
    Q_FOREACH(QString propertyName, superProperties.keys())
    {
        if (!d->superPropertiesCache.contains(propertyName))
        {
            d->superPropertiesCache.insert(propertyName, superProperties.value(propertyName));
        } else {
            d->superPropertiesCache[propertyName] = superProperties.value(propertyName);
        }
    }

    saveSuperProperties();
}

///
/// Register super properties for events, only if no other super property with the
/// same names has already been registered.
///
/// \note Calling registerSuperPropertiesOnce will never overwrite existing properties.
///
/// \param superProperties A QVariantMap containing the super properties to register.
///

void MixpanelPersistentIdentity::registerSuperPropertiesOnce(const QVariantMap& superProperties)
{
    Q_FOREACH(QString propertyName, superProperties.keys())
    {
        if (!d->superPropertiesCache.contains(propertyName))
        {
            d->superPropertiesCache.insert(propertyName, superProperties.value(propertyName));
        }
    }

    saveSuperProperties();
}

///
/// Remove a single superProperty, so that it will not be sent with future calls to track events.
///
/// \note If there is a superProperty registered with the given name, it will be permanently
/// removed from the existing superProperties.
/// To clear all superProperties, use clearSuperProperties()
///
/// \param superPropertyName name of the property to unregister
///

void MixpanelPersistentIdentity::unregisterSuperProperty(const QString& superPropertyName)
{
    if (d->superPropertiesCache.contains(superPropertyName))
    {
        d->superPropertiesCache.remove(superPropertyName);
        saveSuperProperties();
    }
}

///
/// Erase all currently registered superProperties.
///
/// /note Future tracking calls to Mixpanel (even those already queued up but not
/// yet sent to Mixpanel servers) will not be associated with the superProperties registered
/// before this call was made.
///
/// /note To remove a single superProperty, use unregisterSuperProperty(QString)
///
///

void MixpanelPersistentIdentity::clearSuperProperties()
{
    QSettings settings(g_organizationName);
    settings.remove(g_superPropertiesKey);

    d->superPropertiesCache.clear();
}

/// Read the device identity and stores it into the referrerProperties.
/// It will set the event or people distinct id as the BB PIN if they haven't been set.
///

void MixpanelPersistentIdentity::readIdentities()
{
    bb::device::HardwareInfo hardwareInfo;
    bb::ApplicationInfo appInfo;
    bb::platform::PlatformInfo platformInfo;

    d->referrerProperties.insert("mp_lib", "blackberry");
    d->referrerProperties.insert("$os", "BB10");

    if (!platformInfo.osVersion().isEmpty())
        d->referrerProperties.insert("$os_version", platformInfo.osVersion());

    if (!appInfo.version().isEmpty())
        d->referrerProperties.insert("$app_version", appInfo.version());

    if (!hardwareInfo.deviceName().isEmpty())
        d->referrerProperties.insert("Device name", hardwareInfo.deviceName());

    if (!hardwareInfo.modelName().isEmpty())
        d->referrerProperties.insert("$model", hardwareInfo.modelName());

    if (!hardwareInfo.pin().isEmpty())
        d->referrerProperties.insert("PIN", hardwareInfo.pin());

    if (d->eventDistinctId.isEmpty())
        setEventDistinctId(hardwareInfo.pin());

    if (d->peopleDistinctId.isEmpty())
        setPeopleDisctinctId(hardwareInfo.pin());
}

///
/// Loads all the persistent data previously saved.
///

void MixpanelPersistentIdentity::loadPersistentData()
{
    QSettings settings(g_organizationName);
    d->superPropertiesCache = settings.value(g_superPropertiesKey, QVariantMap()).toMap();

    d->peopleDistinctId = settings.value(g_peopleDistinctIdKey, QString()).toString();
}

///
/// Save all the super properties registered to make them persistent.
///

void MixpanelPersistentIdentity::saveSuperProperties()
{
    QSettings settings(g_organizationName);
    settings.setValue(g_superPropertiesKey, d->superPropertiesCache);
}

///
/// Save the distinct people id to make it persistent.
///

void MixpanelPersistentIdentity::saveDistinctPeopleId()
{
    QSettings settings(g_organizationName);
    settings.setValue(g_peopleDistinctIdKey, d->peopleDistinctId);
}

<|endoftext|>