initial commit
This commit is contained in:
commit
4b60ece582
327 changed files with 28286 additions and 0 deletions
36
lib/wModel/CMakeLists.txt
Normal file
36
lib/wModel/CMakeLists.txt
Normal file
|
@ -0,0 +1,36 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(model)
|
||||
|
||||
find_package(Qt5Core REQUIRED)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
set(HEADERS
|
||||
model.h
|
||||
modelstring.h
|
||||
list.h
|
||||
vocabulary.h
|
||||
attributes.h
|
||||
icatalogue.h
|
||||
catalogue.h
|
||||
file/file.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
model.cpp
|
||||
modelstring.cpp
|
||||
list.cpp
|
||||
vocabulary.cpp
|
||||
attributes.cpp
|
||||
icatalogue.cpp
|
||||
catalogue.cpp
|
||||
file/file.cpp
|
||||
)
|
||||
|
||||
add_library(wModel STATIC ${HEADERS} ${SOURCES})
|
||||
|
||||
target_link_libraries(wModel Qt5::Core)
|
||||
target_link_libraries(wModel wSocket)
|
||||
target_link_libraries(wModel wDispatcher)
|
||||
target_link_libraries(wModel wType)
|
60
lib/wModel/attributes.cpp
Normal file
60
lib/wModel/attributes.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "attributes.h"
|
||||
|
||||
M::Attributes::Attributes(const W::Address p_address, QObject* parent):
|
||||
M::Vocabulary(p_address, parent),
|
||||
attributes(new Map())
|
||||
{
|
||||
}
|
||||
|
||||
M::Attributes::~Attributes()
|
||||
{
|
||||
delete attributes;
|
||||
}
|
||||
|
||||
M::Model::ModelType M::Attributes::getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
void M::Attributes::addAttribute(const W::String& key, M::Model* model)
|
||||
{
|
||||
Map::const_iterator itr = attributes->find(key);
|
||||
if (itr != attributes->end()) {
|
||||
throw 1;
|
||||
}
|
||||
|
||||
attributes->insert(std::make_pair(key, model));
|
||||
addModel(model);
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"name", key);
|
||||
vc->insert(u"address", model->getAddress());
|
||||
vc->insert(u"type", W::Uint64(model->getType()));
|
||||
|
||||
insert(key, vc);
|
||||
}
|
||||
|
||||
void M::Attributes::removeAttribute(const W::String& key)
|
||||
{
|
||||
Map::const_iterator itr = attributes->find(key);
|
||||
if (itr == attributes->end()) {
|
||||
throw 1;
|
||||
}
|
||||
M::Model* model = itr->second;
|
||||
attributes->erase(itr);
|
||||
erase(key);
|
||||
removeModel(model);
|
||||
|
||||
delete model;
|
||||
}
|
||||
|
||||
void M::Attributes::setAttribute(const W::String& key, const W::Object& value)
|
||||
{
|
||||
Map::const_iterator itr = attributes->find(key);
|
||||
itr->second->set(value);
|
||||
}
|
||||
|
||||
void M::Attributes::setAttribute(const W::String& key, W::Object* value)
|
||||
{
|
||||
Map::const_iterator itr = attributes->find(key);
|
||||
itr->second->set(value);
|
||||
}
|
32
lib/wModel/attributes.h
Normal file
32
lib/wModel/attributes.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef M_ATTRIBUTES_H
|
||||
#define M_ATTRIBUTES_H
|
||||
|
||||
#include "vocabulary.h"
|
||||
|
||||
#include <wType/string.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace M {
|
||||
class Attributes : public M::Vocabulary
|
||||
{
|
||||
public:
|
||||
Attributes(const W::Address p_address, QObject* parent = 0);
|
||||
~Attributes();
|
||||
|
||||
void addAttribute(const W::String& key, M::Model* model);
|
||||
void removeAttribute(const W::String& key);
|
||||
void setAttribute(const W::String& key, const W::Object& value);
|
||||
void setAttribute(const W::String& key, W::Object* value);
|
||||
|
||||
M::Model::ModelType getType() const override;
|
||||
static const M::Model::ModelType type = attributes;
|
||||
|
||||
private:
|
||||
typedef std::map<W::String, M::Model*> Map;
|
||||
|
||||
Map* attributes;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ATTRIBUTES_H
|
66
lib/wModel/catalogue.cpp
Normal file
66
lib/wModel/catalogue.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include "catalogue.h"
|
||||
|
||||
M::Catalogue::Catalogue(const W::Address p_address, QObject* parent):
|
||||
ICatalogue(p_address, parent),
|
||||
data()
|
||||
{
|
||||
}
|
||||
|
||||
M::Catalogue::~Catalogue()
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t M::Catalogue::addElement(const W::Vocabulary& record)
|
||||
{
|
||||
uint64_t id = M::ICatalogue::addElement(record);
|
||||
|
||||
data.insert(std::make_pair(id, static_cast<W::Vocabulary*>(record.copy())));
|
||||
return id;
|
||||
}
|
||||
|
||||
void M::Catalogue::removeElement(uint64_t id)
|
||||
{
|
||||
M::ICatalogue::removeElement(id);
|
||||
|
||||
Data::const_iterator itr = data.find(id);
|
||||
delete itr->second;
|
||||
data.erase(itr);
|
||||
}
|
||||
|
||||
void M::Catalogue::clear()
|
||||
{
|
||||
M::ICatalogue::clear();
|
||||
|
||||
data.clear();
|
||||
}
|
||||
|
||||
|
||||
W::Vocabulary * M::Catalogue::getElement(uint64_t id)
|
||||
{
|
||||
return static_cast<W::Vocabulary*>(data.at(id)->copy());
|
||||
}
|
||||
std::set<uint64_t> M::Catalogue::getAll() const
|
||||
{
|
||||
std::set<uint64_t> res;
|
||||
|
||||
Data::const_iterator itr = data.begin();
|
||||
Data::const_iterator end = data.end();
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
res.insert(itr->first);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void M::Catalogue::modifyElement(uint64_t id, const W::Vocabulary& newValue)
|
||||
{
|
||||
Data::iterator itr = data.find(id);
|
||||
delete itr->second;
|
||||
itr->second = static_cast<W::Vocabulary*>(newValue.copy());
|
||||
}
|
||||
|
||||
uint64_t M::Catalogue::size() const
|
||||
{
|
||||
return data.size();
|
||||
}
|
29
lib/wModel/catalogue.h
Normal file
29
lib/wModel/catalogue.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef CATALOGUE_H
|
||||
#define CATALOGUE_H
|
||||
|
||||
#include "icatalogue.h"
|
||||
|
||||
namespace M {
|
||||
|
||||
class Catalogue : public ICatalogue {
|
||||
public:
|
||||
Catalogue(const W::Address p_address, QObject* parent = 0);
|
||||
~Catalogue();
|
||||
|
||||
uint64_t addElement(const W::Vocabulary & record) override;
|
||||
void removeElement(uint64_t id) override;
|
||||
void clear() override;
|
||||
W::Vocabulary* getElement(uint64_t id) override;
|
||||
void modifyElement(uint64_t id, const W::Vocabulary & newValue) override;
|
||||
uint64_t size() const override;
|
||||
|
||||
protected:
|
||||
std::set<uint64_t> getAll() const override;
|
||||
|
||||
private:
|
||||
typedef std::map<uint64_t, W::Vocabulary*> Data;
|
||||
Data data;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CATALOGUE_H
|
86
lib/wModel/file/file.cpp
Normal file
86
lib/wModel/file/file.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include "file.h"
|
||||
#include <iostream>
|
||||
|
||||
QMimeDatabase M::File::mimeDB;
|
||||
|
||||
M::File::File(W::Blob* p_file, const W::Address& addr, QObject* parent):
|
||||
M::Model(addr, parent),
|
||||
additional(),
|
||||
file(p_file)
|
||||
{
|
||||
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::File::_h_get);
|
||||
W::Handler* getAdditional = W::Handler::create(address + W::Address({u"getAdditional"}), this, &M::File::_h_getAdditional);
|
||||
|
||||
addHandler(get);
|
||||
addHandler(getAdditional);
|
||||
}
|
||||
|
||||
M::File::~File()
|
||||
{
|
||||
delete file;
|
||||
}
|
||||
|
||||
M::Model::ModelType M::File::getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
void M::File::initAdditional(const W::String& p_mime)
|
||||
{
|
||||
additional.clear();
|
||||
|
||||
additional.insert(u"size", new W::Uint64(file->size()));
|
||||
additional.insert(u"mimeType", p_mime);
|
||||
}
|
||||
|
||||
void M::File::set(const W::Object& value)
|
||||
{
|
||||
set(value.copy());
|
||||
}
|
||||
|
||||
void M::File::set(W::Object* value)
|
||||
{
|
||||
delete file;
|
||||
file = static_cast<W::Blob*>(value);
|
||||
|
||||
QMimeType mt = mimeDB.mimeTypeForData(file->byteArray());
|
||||
initAdditional(W::String(mt.name().toStdString()));
|
||||
|
||||
W::Vocabulary* vc = static_cast<W::Vocabulary*>(additional.copy());
|
||||
|
||||
broadcast(vc, W::Address({u"getAdditional"}));
|
||||
}
|
||||
|
||||
void M::File::h_getAdditional(const W::Event& ev)
|
||||
{
|
||||
W::Vocabulary* vc = static_cast<W::Vocabulary*>(additional.copy());
|
||||
|
||||
response(vc, W::Address({u"getAdditional"}), ev);
|
||||
}
|
||||
|
||||
void M::File::h_subscribe(const W::Event& ev)
|
||||
{
|
||||
M::Model::h_subscribe(ev);
|
||||
|
||||
h_getAdditional(ev);
|
||||
}
|
||||
|
||||
void M::File::h_get(const W::Event& ev)
|
||||
{
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"additional", additional.copy());
|
||||
vc->insert(u"data", file->copy());
|
||||
|
||||
response(vc, W::Address({u"get"}), ev);
|
||||
}
|
||||
|
||||
M::File * M::File::create(W::Blob* blob, const W::Address& addr, QObject* parent)
|
||||
{
|
||||
M::File* out;
|
||||
|
||||
QMimeType mt = mimeDB.mimeTypeForData(blob->byteArray());
|
||||
out = new File(blob, addr, parent);
|
||||
|
||||
out->initAdditional(W::String(mt.name().toStdString()));
|
||||
return out;
|
||||
}
|
44
lib/wModel/file/file.h
Normal file
44
lib/wModel/file/file.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
/**
|
||||
* @todo write docs
|
||||
*/
|
||||
|
||||
#include <wModel/model.h>
|
||||
|
||||
#include <wType/blob.h>
|
||||
#include <QtCore/QMimeDatabase>
|
||||
|
||||
namespace M {
|
||||
|
||||
class File: public Model {
|
||||
protected:
|
||||
File(W::Blob* p_file, const W::Address& addr, QObject* parent = 0);
|
||||
public:
|
||||
~File();
|
||||
|
||||
void set(const W::Object & value) override;
|
||||
void set(W::Object * value) override;
|
||||
|
||||
M::Model::ModelType getType() const override;
|
||||
static const M::Model::ModelType type = file;
|
||||
|
||||
static File* create(W::Blob* blob, const W::Address& addr, QObject* parent = 0);
|
||||
|
||||
protected:
|
||||
virtual void initAdditional(const W::String& p_mime);
|
||||
void h_subscribe(const W::Event & ev) override;
|
||||
|
||||
handler(get);
|
||||
handler(getAdditional);
|
||||
|
||||
protected:
|
||||
W::Vocabulary additional;
|
||||
W::Blob* file;
|
||||
|
||||
static QMimeDatabase mimeDB;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // FILE_H
|
469
lib/wModel/icatalogue.cpp
Normal file
469
lib/wModel/icatalogue.cpp
Normal file
|
@ -0,0 +1,469 @@
|
|||
#include "icatalogue.h"
|
||||
|
||||
const std::set<uint64_t> M::ICatalogue::empty = std::set<uint64_t>();
|
||||
|
||||
M::ICatalogue::ICatalogue(const W::Address p_address, QObject* parent):
|
||||
M::Model(p_address, parent),
|
||||
subscribeMember(W::Handler::create(W::Address({}), this, &M::ICatalogue::_h_subscribeMember)),
|
||||
indexes(),
|
||||
lastIndex(0),
|
||||
activeChildren()
|
||||
{
|
||||
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::ICatalogue::_h_get);
|
||||
W::Handler* add = W::Handler::create(address + W::Address({u"add"}), this, &M::ICatalogue::_h_add);
|
||||
W::Handler* update = W::Handler::create(address + W::Address({u"update"}), this, &M::ICatalogue::_h_update);
|
||||
|
||||
addHandler(get);
|
||||
addHandler(add);
|
||||
addHandler(update);
|
||||
}
|
||||
|
||||
M::ICatalogue::~ICatalogue()
|
||||
{
|
||||
delete subscribeMember;
|
||||
|
||||
IndexMap::const_iterator itr = indexes.begin();
|
||||
IndexMap::const_iterator end = indexes.end();
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
delete itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
void M::ICatalogue::clear()
|
||||
{
|
||||
lastIndex = 0;
|
||||
IndexMap::const_iterator itr = indexes.begin();
|
||||
IndexMap::const_iterator end = indexes.end();
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
itr->second->clear();
|
||||
}
|
||||
|
||||
if (registered) {
|
||||
broadcast(new W::Vocabulary(), W::Address{u"clear"});
|
||||
}
|
||||
|
||||
emit countChange(0);
|
||||
}
|
||||
|
||||
|
||||
void M::ICatalogue::addIndex(const W::String& fieldName, W::Object::objectType fieldType)
|
||||
{
|
||||
IndexMap::const_iterator itr = indexes.find(fieldName);
|
||||
if (itr != indexes.end()) {
|
||||
throw 2;
|
||||
}
|
||||
|
||||
switch (fieldType) {
|
||||
case W::Object::uint64:
|
||||
indexes.insert(std::make_pair(fieldName, new Index<W::Uint64>()));
|
||||
break;
|
||||
case W::Object::string:
|
||||
indexes.insert(std::make_pair(fieldName, new Index<W::String>()));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 3;
|
||||
}
|
||||
}
|
||||
|
||||
const std::set<uint64_t> & M::ICatalogue::find(const W::String& indexName, const W::Object& value) const
|
||||
{
|
||||
IndexMap::const_iterator itr = indexes.find(indexName);
|
||||
if (itr == indexes.end()) {
|
||||
throw 4;
|
||||
}
|
||||
|
||||
return itr->second->find(value);
|
||||
}
|
||||
|
||||
|
||||
std::set<uint64_t> M::ICatalogue::find(const W::Vocabulary& value) const
|
||||
{
|
||||
W::Vector keys = value.keys();
|
||||
int size = keys.length();
|
||||
|
||||
std::set<uint64_t> result;
|
||||
bool first = true;
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
const W::String& key = static_cast<const W::String&>(keys.at(i));
|
||||
IndexMap::const_iterator itr = indexes.find(key);
|
||||
if (itr == indexes.end()) {
|
||||
throw 4;
|
||||
}
|
||||
if (first) {
|
||||
result = itr->second->find(value.at(key));
|
||||
first = false;
|
||||
} else {
|
||||
std::set<uint64_t> copy = result;
|
||||
result.clear();
|
||||
const std::set<uint64_t>& current = itr->second->find(value.at(key));
|
||||
std::set_intersection(copy.begin(), copy.end(), current.begin(), current.end(), std::inserter(result, result.end()));
|
||||
}
|
||||
|
||||
if (result.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
M::Model::ModelType M::ICatalogue::getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
uint64_t M::ICatalogue::addElement(const W::Vocabulary& record)
|
||||
{
|
||||
IndexMap::const_iterator itr = indexes.begin();
|
||||
IndexMap::const_iterator end = indexes.end();
|
||||
|
||||
++lastIndex;
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
itr->second->add(record.at(itr->first), lastIndex);
|
||||
}
|
||||
|
||||
Map::const_iterator sItr = subscribers->begin();
|
||||
Map::const_iterator sEnd = subscribers->end();
|
||||
|
||||
for (; sItr != sEnd; ++sItr) {
|
||||
SMap::const_iterator oItr = sItr->second.begin();
|
||||
SMap::const_iterator oEnd = sItr->second.end();
|
||||
|
||||
for (; oItr != oEnd; ++oItr) {
|
||||
const W::Vocabulary& params = oItr->second;
|
||||
if (params.has(u"filter")) {
|
||||
processAddElement(lastIndex, record, oItr, sItr->first);
|
||||
} else {
|
||||
uint64_t bid = getInsertingNeighbour(oItr->second, record, lastIndex, getAll());
|
||||
|
||||
W::Address dest = oItr->first + W::Address({u"addElement"});
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"id", new W::Uint64(lastIndex));
|
||||
if (bid != 0) {
|
||||
vc->insert(u"before", new W::Uint64(bid));
|
||||
}
|
||||
send(vc, dest, sItr->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit countChange(size() + 1);
|
||||
return lastIndex;
|
||||
}
|
||||
|
||||
void M::ICatalogue::removeElement(uint64_t id)
|
||||
{
|
||||
IndexMap::const_iterator itr = indexes.begin();
|
||||
IndexMap::const_iterator end = indexes.end();
|
||||
|
||||
W::Vocabulary* value = getElement(id);
|
||||
|
||||
Map::const_iterator sItr = subscribers->begin();
|
||||
Map::const_iterator sEnd = subscribers->end();
|
||||
|
||||
for (; sItr != sEnd; ++sItr) {
|
||||
SMap::const_iterator oItr = sItr->second.begin();
|
||||
SMap::const_iterator oEnd = sItr->second.end();
|
||||
|
||||
for (; oItr != oEnd; ++oItr) {
|
||||
const W::Vocabulary& params = oItr->second;
|
||||
if (params.has(u"filter")) {
|
||||
const W::Vocabulary& filter = static_cast<const W::Vocabulary&>(params.at(u"filter"));
|
||||
std::set<uint64_t> set = find(filter);
|
||||
std::set<uint64_t>::const_iterator idItr = set.find(id);
|
||||
if (idItr != set.end()) {
|
||||
W::Address dest = oItr->first + W::Address({u"removeElement"});
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"id", new W::Uint64(id));
|
||||
send(vc, dest, sItr->first);
|
||||
}
|
||||
} else {
|
||||
W::Address dest = oItr->first + W::Address({u"removeElement"});
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"id", new W::Uint64(id));
|
||||
send(vc, dest, sItr->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
itr->second->remove(value->at(itr->first), id);
|
||||
}
|
||||
|
||||
std::map<uint64_t, M::Vocabulary*>::const_iterator aItr = activeChildren.find(id);
|
||||
if (aItr != activeChildren.end()) {
|
||||
removeModel(aItr->second);
|
||||
aItr->second->deleteLater();
|
||||
activeChildren.erase(aItr);
|
||||
}
|
||||
|
||||
emit countChange(size() - 1);
|
||||
delete value;
|
||||
}
|
||||
|
||||
void M::ICatalogue::h_get(const W::Event& ev)
|
||||
{
|
||||
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
|
||||
const W::Vocabulary& params = static_cast<const W::Vocabulary&>(vc.at(u"params"));
|
||||
|
||||
std::set<uint64_t> set;
|
||||
if (params.has(u"filter")) {
|
||||
const W::Vocabulary& filter = static_cast<const W::Vocabulary&>(params.at(u"filter"));
|
||||
set = find(filter);
|
||||
} else {
|
||||
set = getAll();
|
||||
}
|
||||
|
||||
W::Vocabulary* rvc = new W::Vocabulary;
|
||||
if (params.has(u"sorting")) {
|
||||
const W::Vocabulary& sorting = static_cast<const W::Vocabulary&>(params.at(u"sorting"));
|
||||
const W::String& field = static_cast<const W::String&>(sorting.at(u"field"));
|
||||
bool ascending = static_cast<const W::Boolean&>(sorting.at(u"ascending"));
|
||||
rvc->insert(u"data", indexes.at(field)->sort(set, ascending));
|
||||
} else {
|
||||
W::Vector* order = new W::Vector();
|
||||
std::set<uint64_t>::const_iterator itr = set.begin();
|
||||
std::set<uint64_t>::const_iterator end = set.end();
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
order->push(W::Uint64(*itr));
|
||||
}
|
||||
rvc->insert(u"data", order);
|
||||
}
|
||||
|
||||
response(rvc, W::Address({u"get"}), ev);
|
||||
}
|
||||
|
||||
void M::ICatalogue::h_subscribe(const W::Event& ev)
|
||||
{
|
||||
M::Model::h_subscribe(ev);
|
||||
|
||||
h_get(ev);
|
||||
}
|
||||
|
||||
void M::ICatalogue::set(const W::Object& value)
|
||||
{
|
||||
throw 14; //what do you expect here? not implemented, and not sure it ever would be
|
||||
}
|
||||
|
||||
void M::ICatalogue::set(W::Object* value)
|
||||
{
|
||||
set(*value);
|
||||
}
|
||||
|
||||
void M::ICatalogue::h_add(const W::Event& ev)
|
||||
{
|
||||
addElement(static_cast<const W::Vocabulary&>(ev.getData()));
|
||||
}
|
||||
|
||||
void M::ICatalogue::h_update(const W::Event& ev)
|
||||
{
|
||||
const W::Vocabulary& data = static_cast<const W::Vocabulary&>(ev.getData());
|
||||
|
||||
const W::Uint64& id = static_cast<const W::Uint64&>(data.at(u"id"));
|
||||
const W::Vocabulary& newValue = static_cast<const W::Vocabulary&>(data.at(u"value"));
|
||||
W::Vector affectedKeys = newValue.keys();
|
||||
|
||||
W::Vocabulary* oldValue = getElement(id);
|
||||
W::Vocabulary* modifiedValue = W::Vocabulary::extend(*oldValue, newValue);
|
||||
|
||||
modifyElement(id, *modifiedValue);
|
||||
|
||||
std::map<uint64_t, M::Vocabulary*>::const_iterator itr = activeChildren.find(id);
|
||||
if (itr != activeChildren.end()) {
|
||||
itr->second->set(modifiedValue);
|
||||
}
|
||||
|
||||
Map::const_iterator sItr = subscribers->begin();
|
||||
Map::const_iterator sEnd = subscribers->end();
|
||||
|
||||
for (; sItr != sEnd; ++sItr) {
|
||||
SMap::const_iterator oItr = sItr->second.begin();
|
||||
SMap::const_iterator oEnd = sItr->second.end();
|
||||
|
||||
for (; oItr != oEnd; ++oItr) {
|
||||
const W::Vocabulary& params = oItr->second;
|
||||
if (params.has(u"filter")) {
|
||||
const W::Vocabulary& filter = static_cast<const W::Vocabulary&>(params.at(u"filter"));
|
||||
bool matched = match(*oldValue, filter);
|
||||
bool matching = match(*modifiedValue, filter);
|
||||
|
||||
if (matched && !matching) {
|
||||
W::Address dest = oItr->first + W::Address({u"removeElement"});
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"id", new W::Uint64(id));
|
||||
send(vc, dest, sItr->first);
|
||||
} else if (!matched && matching) {
|
||||
processAddElement(id, *modifiedValue, oItr, sItr->first);
|
||||
} else if (matched && matching) {
|
||||
std::set<uint64_t> set = find(filter);
|
||||
uint64_t cbid = getInsertingNeighbour(params, *oldValue, id, set);
|
||||
uint64_t bid = getInsertingNeighbour(params, *modifiedValue, id, set);
|
||||
|
||||
if (cbid != bid) {
|
||||
W::Address dest = oItr->first + W::Address({u"moveElement"});
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"id", new W::Uint64(id));
|
||||
if (id != 0) {
|
||||
vc->insert(u"before", new W::Uint64(bid));
|
||||
}
|
||||
send(vc, dest, sItr->first);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (params.has(u"sorting")) {
|
||||
std::set<uint64_t> set = getAll();
|
||||
uint64_t cbid = getInsertingNeighbour(params, *oldValue, id, set);
|
||||
uint64_t bid = getInsertingNeighbour(params, *modifiedValue, id, set);
|
||||
|
||||
if (cbid != bid) {
|
||||
W::Address dest = oItr->first + W::Address({u"moveElement"});
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"id", new W::Uint64(id));
|
||||
if (id != 0) {
|
||||
vc->insert(u"before", new W::Uint64(bid));
|
||||
}
|
||||
send(vc, dest, sItr->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void M::ICatalogue::h_subscribeMember(const W::Event& ev)
|
||||
{
|
||||
const W::Address& addr = ev.getDestination();
|
||||
W::Address lastHops = addr << address.length();
|
||||
|
||||
if (lastHops.length() == 2 && (lastHops.ends(W::Address{u"subscribe"}) || lastHops.ends(W::Address{u"get"}))) {
|
||||
W::Vocabulary* record;
|
||||
try {
|
||||
uint64_t id = lastHops.front().toUint64();
|
||||
record = getElement(id);
|
||||
if (lastHops.ends(W::Address{u"subscribe"})) {
|
||||
M::Vocabulary* modelRecord = new M::Vocabulary(record, address + lastHops >> 1);
|
||||
addModel(modelRecord);
|
||||
activeChildren.insert(std::make_pair(id, modelRecord));
|
||||
modelRecord->_h_subscribe(ev);
|
||||
} else {
|
||||
W::Vocabulary* vc = new W::Vocabulary;
|
||||
vc->insert(u"data", record);
|
||||
|
||||
fakeResponse(vc, W::Address({u"get"}), addr >> 1, ev);
|
||||
}
|
||||
} catch(int err) {
|
||||
if (err == 3) {
|
||||
emit serviceMessage(QString("An attempt to create and subscribe record model in catalogue, but it is not found. Event: ") + ev.toString().c_str());
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} catch (const std::invalid_argument& err) {
|
||||
emit serviceMessage(QString("Strange event in custom handler of catalogue ") + ev.toString().c_str());
|
||||
}
|
||||
} else {
|
||||
emit serviceMessage(QString("Strange event in custom handler of catalogue ") + ev.toString().c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool M::ICatalogue::match(const W::Vocabulary& value, const W::Vocabulary& filter)
|
||||
{
|
||||
bool m = true;
|
||||
W::Vector keys = filter.keys();
|
||||
for (int i = 0; i < keys.length(); ++i) {
|
||||
const W::String& key = static_cast<const W::String&>(keys.at(i));
|
||||
if (filter.at(key) != value.at(key)) {
|
||||
m = false;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void M::ICatalogue::processAddElement(uint64_t id, const W::Vocabulary& value, SMap::const_iterator subscriberIterator, uint64_t socketId)
|
||||
{
|
||||
const W::Address& addr = subscriberIterator->first;
|
||||
const W::Vocabulary& params = subscriberIterator->second;
|
||||
const W::Vocabulary& filter = static_cast<const W::Vocabulary&>(params.at(u"filter"));
|
||||
|
||||
std::set<uint64_t> set = find(filter);
|
||||
std::set<uint64_t>::const_iterator idItr = set.find(id);
|
||||
if (idItr != set.end()) { //to make sure if subscriber cares
|
||||
uint64_t bid = getInsertingNeighbour(params, value, id, set);
|
||||
|
||||
W::Address dest = addr + W::Address({u"addElement"});
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"id", new W::Uint64(id));
|
||||
if (id != 0) {
|
||||
vc->insert(u"before", new W::Uint64(bid));
|
||||
}
|
||||
send(vc, dest, socketId);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t M::ICatalogue::getInsertingNeighbour(const W::Vocabulary& params, const W::Vocabulary& record, uint64_t id, const std::set<uint64_t>& allowed) const
|
||||
{
|
||||
uint64_t bid;
|
||||
if (params.has(u"sorting")) {
|
||||
if (allowed.empty()) {
|
||||
bid = 0;
|
||||
} else {
|
||||
const W::Vocabulary& sorting = static_cast<const W::Vocabulary&>(params.at(u"sorting"));
|
||||
const W::String& field = static_cast<const W::String&>(sorting.at(u"field"));
|
||||
bool ascending = static_cast<const W::Boolean&>(sorting.at(u"ascending"));
|
||||
|
||||
uint64_t foundId = id;
|
||||
do {
|
||||
if (ascending) {
|
||||
foundId = indexes.at(field)->getNext(foundId, record.at(field));
|
||||
} else {
|
||||
foundId = indexes.at(field)->getPrev(foundId, record.at(field));
|
||||
}
|
||||
} while (allowed.find(foundId) == allowed.end() || foundId != 0); //to make sure, that id folowing the inserting also present in the
|
||||
bid = foundId; //subscribers filter result
|
||||
}
|
||||
} else {
|
||||
std::set<uint64_t>::const_iterator idItr = allowed.find(id);
|
||||
if (idItr == allowed.end()) {
|
||||
bid = 0;
|
||||
} else {
|
||||
++idItr;
|
||||
if (idItr == allowed.end()) {
|
||||
bid = 0;
|
||||
} else {
|
||||
bid = *idItr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bid;
|
||||
}
|
||||
|
||||
M::ICatalogue::AbstractIndex::TypeError::TypeError(const std::string& name, const std::string& method, W::Object::objectType myType, W::Object::objectType valueType):
|
||||
Utils::Exception(),
|
||||
name(name),
|
||||
method(method),
|
||||
myType(myType),
|
||||
valueType(valueType)
|
||||
{}
|
||||
|
||||
std::string M::ICatalogue::AbstractIndex::TypeError::getMessage() const
|
||||
{
|
||||
std::string msg = "An attempt to call Catalogue Index of ";
|
||||
msg += name;
|
||||
msg += " method \"";
|
||||
msg += method;
|
||||
msg += "\" with value type of ";
|
||||
msg += W::Object::getTypeName(valueType);
|
||||
msg += " but this index values supposed to have type ";
|
||||
msg += W::Object::getTypeName(myType);
|
||||
|
||||
return msg;
|
||||
}
|
316
lib/wModel/icatalogue.h
Normal file
316
lib/wModel/icatalogue.h
Normal file
|
@ -0,0 +1,316 @@
|
|||
#ifndef ICATALOGUE_H
|
||||
#define ICATALOGUE_H
|
||||
|
||||
#include "model.h"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include <wModel/vocabulary.h>
|
||||
#include <utils/exception.h>
|
||||
|
||||
namespace M {
|
||||
class ICatalogue : public M::Model
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
class AbstractIndex;
|
||||
public:
|
||||
ICatalogue(const W::Address p_address, QObject* parent = 0);
|
||||
~ICatalogue();
|
||||
|
||||
virtual uint64_t addElement(const W::Vocabulary& record);
|
||||
virtual void removeElement(uint64_t id);
|
||||
virtual W::Vocabulary* getElement(uint64_t id) = 0;
|
||||
virtual void modifyElement(uint64_t id, const W::Vocabulary& newValue) = 0;
|
||||
virtual uint64_t size() const = 0;
|
||||
virtual void clear();
|
||||
|
||||
virtual void addIndex(const W::String& fieldName, W::Object::objectType fieldType);
|
||||
const std::set<uint64_t>& find(const W::String& indexName, const W::Object& value) const;
|
||||
std::set<uint64_t> find(const W::Vocabulary& value) const;
|
||||
|
||||
M::Model::ModelType getType() const override;
|
||||
static const M::Model::ModelType type = catalogue;
|
||||
void set(const W::Object & value) override;
|
||||
void set(W::Object * value) override;
|
||||
|
||||
W::Handler* subscribeMember;
|
||||
handler(subscribeMember);
|
||||
|
||||
static bool match(const W::Vocabulary& value, const W::Vocabulary& filter);
|
||||
static const std::set<uint64_t> empty;
|
||||
|
||||
signals:
|
||||
void countChange(uint64_t count);
|
||||
|
||||
protected:
|
||||
virtual std::set<uint64_t> getAll() const = 0;
|
||||
void h_subscribe(const W::Event & ev) override;
|
||||
|
||||
handler(get);
|
||||
handler(add);
|
||||
handler(update);
|
||||
|
||||
typedef std::map<W::String, AbstractIndex*> IndexMap;
|
||||
IndexMap indexes;
|
||||
|
||||
private:
|
||||
uint64_t lastIndex;
|
||||
std::map<uint64_t, M::Vocabulary*> activeChildren;
|
||||
|
||||
void processAddElement(uint64_t id, const W::Vocabulary& value, SMap::const_iterator subscriberIterator, uint64_t socketId);
|
||||
uint64_t getInsertingNeighbour(const W::Vocabulary& params, const W::Vocabulary& record, uint64_t id, const std::set<uint64_t>& allowed = empty) const;
|
||||
|
||||
protected:
|
||||
class AbstractIndex {
|
||||
public:
|
||||
AbstractIndex(W::Object::objectType vt): valueType(vt) {}
|
||||
virtual ~AbstractIndex() {}
|
||||
|
||||
virtual const std::set<uint64_t>& find(const W::Object& value) const = 0;
|
||||
virtual void add(const W::Object& value, uint64_t id) = 0;
|
||||
virtual void remove(const W::Object & value, uint64_t id) = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual W::Vector sort(const std::set<uint64_t>& set, bool ascending) = 0;
|
||||
virtual uint64_t getNext(uint64_t id, const W::Object& value) = 0;
|
||||
virtual uint64_t getPrev(uint64_t id, const W::Object& value) = 0;
|
||||
|
||||
W::Object::objectType valueType;
|
||||
|
||||
protected:
|
||||
class TypeError : public Utils::Exception {
|
||||
public:
|
||||
TypeError(const std::string& name, const std::string& method, W::Object::objectType myType, W::Object::objectType valueType);
|
||||
|
||||
std::string getMessage() const;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::string method;
|
||||
W::Object::objectType myType;
|
||||
W::Object::objectType valueType;
|
||||
};
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class Index : public AbstractIndex {
|
||||
public:
|
||||
Index();
|
||||
~Index();
|
||||
|
||||
const std::set<uint64_t>& find(const W::Object& value) const override;
|
||||
void add(const W::Object & value, uint64_t id) override;
|
||||
void remove(const W::Object & value, uint64_t id) override;
|
||||
void clear() override;
|
||||
W::Vector sort(const std::set<uint64_t> & set, bool ascending) override;
|
||||
uint64_t getNext(uint64_t id, const W::Object& value) override;
|
||||
uint64_t getPrev(uint64_t id, const W::Object& value) override;
|
||||
|
||||
private:
|
||||
typedef std::map<T, std::set<uint64_t>> Map;
|
||||
|
||||
Map values;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
ICatalogue::Index<T>::Index():
|
||||
ICatalogue::AbstractIndex(T::type),
|
||||
values()
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
ICatalogue::Index<T>::~Index()
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const std::set<uint64_t> & ICatalogue::Index<T>::find(const W::Object& value) const
|
||||
{
|
||||
if (value.getType() != valueType) {
|
||||
throw new TypeError("Unknown", "find", valueType, value.getType()); //todo replace that unknown stuff, find a way to provide index name
|
||||
}
|
||||
|
||||
const T& val = static_cast<const T&>(value);
|
||||
typename std::map<T, std::set<uint64_t>>::const_iterator itr = values.find(val);
|
||||
|
||||
if (itr == values.end()) {
|
||||
return ICatalogue::empty;
|
||||
} else {
|
||||
return itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ICatalogue::Index<T>::add(const W::Object& value, uint64_t id)
|
||||
{
|
||||
if (value.getType() != valueType) {
|
||||
throw new TypeError("Unknown", "add", valueType, value.getType());
|
||||
}
|
||||
|
||||
const T& val = static_cast<const T&>(value);
|
||||
typename std::map<T, std::set<uint64_t>>::iterator itr = values.find(val);
|
||||
if (itr == values.end()) {
|
||||
itr = values.insert(std::make_pair(val, std::set<uint64_t>())).first;
|
||||
}
|
||||
itr->second.insert(id);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ICatalogue::Index<T>::remove(const W::Object& value, uint64_t id)
|
||||
{
|
||||
if (value.getType() != valueType) {
|
||||
throw new TypeError("Unknown", "remove", valueType, value.getType());
|
||||
}
|
||||
const T& val = static_cast<const T&>(value);
|
||||
typename std::map<T, std::set<uint64_t>>::iterator itr = values.find(val);
|
||||
if (itr != values.end()) {
|
||||
std::set<uint64_t>& set = itr->second;
|
||||
if (set.size() == 1) {
|
||||
values.erase(itr);
|
||||
} else {
|
||||
std::set<uint64_t>::const_iterator hint = set.find(id);
|
||||
set.erase(hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ICatalogue::Index<T>::clear()
|
||||
{
|
||||
values.clear();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
W::Vector ICatalogue::Index<T>::sort(const std::set<uint64_t> & set, bool ascending) //TODO this needs an optimization
|
||||
{
|
||||
W::Vector res;
|
||||
std::set<uint64_t>::const_iterator sEnd = set.end();
|
||||
uint64_t size = set.size();
|
||||
|
||||
if (size == 0) {
|
||||
return res;
|
||||
} else if (size == 1) {
|
||||
res.push(W::Uint64(*(set.begin())));
|
||||
return res;
|
||||
}
|
||||
if (ascending) {
|
||||
typename std::map<T, std::set<uint64_t>>::const_iterator itr = values.begin();
|
||||
typename std::map<T, std::set<uint64_t>>::const_iterator end = values.end();
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
if (size == res.size()) {
|
||||
break;
|
||||
}
|
||||
const std::set<uint64_t>& chunk = itr->second;
|
||||
|
||||
std::set<uint64_t>::const_iterator cItr = chunk.begin();
|
||||
std::set<uint64_t>::const_iterator cEnd = chunk.end();
|
||||
for (; cItr != cEnd; ++cItr) {
|
||||
uint64_t id = *cItr;
|
||||
if (set.find(id) != sEnd) {
|
||||
res.push(W::Uint64(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
typename std::map<T, std::set<uint64_t>>::reverse_iterator itr = values.rbegin();
|
||||
typename std::map<T, std::set<uint64_t>>::reverse_iterator end = values.rend();
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
if (size == res.size()) {
|
||||
break;
|
||||
}
|
||||
const std::set<uint64_t>& chunk = itr->second;
|
||||
|
||||
std::set<uint64_t>::const_iterator cItr = chunk.begin();
|
||||
std::set<uint64_t>::const_iterator cEnd = chunk.end();
|
||||
for (; cItr != cEnd; ++cItr) {
|
||||
uint64_t id = *cItr;
|
||||
if (set.find(id) != sEnd) {
|
||||
res.push(W::Uint64(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
uint64_t ICatalogue::Index<T>::getNext(uint64_t id, const W::Object& value)
|
||||
{
|
||||
if (value.getType() != valueType) {
|
||||
throw new TypeError("Unknown", "getNext", valueType, value.getType());
|
||||
}
|
||||
const T& val = static_cast<const T&>(value);
|
||||
typename std::map<T, std::set<uint64_t>>::iterator itr = values.find(val);
|
||||
if (itr == values.end()) {
|
||||
throw 2; //this is not suppose to happen!
|
||||
}
|
||||
const std::set<uint64_t>& set = itr->second;
|
||||
std::set<uint64_t>::const_iterator sItr = set.find(id);
|
||||
if (sItr == set.end()) {
|
||||
throw 2; //not suppose to happen!
|
||||
}
|
||||
++sItr;
|
||||
if (sItr == set.end()) {
|
||||
++itr;
|
||||
bool found = false;
|
||||
while (itr != values.end()) {
|
||||
if (itr->second.size() != 0) {
|
||||
sItr = set.begin();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
if (!found) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return *sItr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
uint64_t ICatalogue::Index<T>::getPrev(uint64_t id, const W::Object& value)
|
||||
{
|
||||
if (value.getType() != valueType) {
|
||||
throw new TypeError("Unknown", "getPrev", valueType, value.getType());
|
||||
}
|
||||
const T& val = static_cast<const T&>(value);
|
||||
typename std::map<T, std::set<uint64_t>>::iterator itr = values.find(val);
|
||||
if (itr == values.end()) {
|
||||
throw 2; //this is not suppose to happen!
|
||||
}
|
||||
const std::set<uint64_t>& set = itr->second;
|
||||
std::set<uint64_t>::const_iterator sItr = set.find(id);
|
||||
if (sItr == set.end()) {
|
||||
throw 2; //not suppose to happen!
|
||||
}
|
||||
if (sItr == set.begin()) {
|
||||
bool found = false;
|
||||
while (itr != values.begin()) {
|
||||
--itr;
|
||||
if (itr->second.size() != 0) {
|
||||
sItr = set.end();
|
||||
--sItr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
--sItr;
|
||||
}
|
||||
return *sItr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ICATALOGUE_H
|
100
lib/wModel/list.cpp
Normal file
100
lib/wModel/list.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
#include "list.h"
|
||||
|
||||
M::List::List(const W::Address p_address, QObject* parent):
|
||||
M::Model(p_address, parent),
|
||||
data(new W::Vector())
|
||||
{
|
||||
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::List::_h_get);
|
||||
addHandler(get);
|
||||
}
|
||||
|
||||
M::List::~List()
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
void M::List::h_subscribe(const W::Event& ev)
|
||||
{
|
||||
M::Model::h_subscribe(ev);
|
||||
|
||||
h_get(ev);
|
||||
}
|
||||
|
||||
void M::List::h_get(const W::Event& ev)
|
||||
{
|
||||
W::Vocabulary* vc = new W::Vocabulary;
|
||||
vc->insert(u"data", data->copy());
|
||||
|
||||
response(vc, W::Address({u"get"}), ev);
|
||||
}
|
||||
|
||||
void M::List::push(const W::Object& obj)
|
||||
{
|
||||
data->push(obj);
|
||||
|
||||
if (registered) {
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"data", obj);
|
||||
|
||||
broadcast(vc, W::Address{u"push"});
|
||||
}
|
||||
}
|
||||
|
||||
void M::List::push(W::Object* obj)
|
||||
{
|
||||
data->push(obj);
|
||||
|
||||
if (registered) {
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"data", obj->copy());
|
||||
|
||||
broadcast(vc, W::Address{u"push"});
|
||||
}
|
||||
}
|
||||
|
||||
void M::List::clear()
|
||||
{
|
||||
data->clear();
|
||||
|
||||
if (registered) {
|
||||
broadcast(new W::Vocabulary(), W::Address{u"clear"});
|
||||
}
|
||||
}
|
||||
|
||||
M::Model::ModelType M::List::getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
void M::List::set(const W::Object& value)
|
||||
{
|
||||
delete data;
|
||||
data = static_cast<W::Vector*>(value.copy());
|
||||
|
||||
W::Vocabulary* vc = new W::Vocabulary;
|
||||
vc->insert(u"data", data->copy());
|
||||
|
||||
broadcast(vc, W::Address({u"get"}));
|
||||
}
|
||||
|
||||
void M::List::set(W::Object* value)
|
||||
{
|
||||
delete data;
|
||||
data = static_cast<W::Vector*>(value);
|
||||
|
||||
W::Vocabulary* vc = new W::Vocabulary;
|
||||
vc->insert(u"data", data->copy());
|
||||
|
||||
broadcast(vc, W::Address({u"get"}));
|
||||
}
|
||||
|
||||
uint64_t M::List::size() const
|
||||
{
|
||||
return data->size();
|
||||
}
|
||||
|
||||
const W::Object & M::List::at(uint64_t index) const
|
||||
{
|
||||
return data->at(index);
|
||||
}
|
||||
|
41
lib/wModel/list.h
Normal file
41
lib/wModel/list.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef M_LIST_H
|
||||
#define M_LIST_H
|
||||
|
||||
#include "model.h"
|
||||
|
||||
#include <wType/object.h>
|
||||
#include <wType/address.h>
|
||||
#include <wType/vector.h>
|
||||
|
||||
namespace M {
|
||||
class List : public M::Model
|
||||
{
|
||||
public:
|
||||
List(const W::Address p_address, QObject* parent = 0);
|
||||
~List();
|
||||
|
||||
void push(const W::Object& obj);
|
||||
void push(W::Object* obj);
|
||||
void clear();
|
||||
|
||||
uint64_t size() const;
|
||||
const W::Object& at(uint64_t index) const;
|
||||
|
||||
void set(const W::Object & value) override;
|
||||
void set(W::Object * value) override;
|
||||
|
||||
M::Model::ModelType getType() const override;
|
||||
static const M::Model::ModelType type = list;
|
||||
|
||||
protected:
|
||||
void h_subscribe(const W::Event & ev) override;
|
||||
|
||||
handler(get);
|
||||
|
||||
private:
|
||||
W::Vector* data;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // M_LIST_H
|
339
lib/wModel/model.cpp
Normal file
339
lib/wModel/model.cpp
Normal file
|
@ -0,0 +1,339 @@
|
|||
#include "model.h"
|
||||
|
||||
M::Model::Model(const W::Address p_address, QObject* parent):
|
||||
QObject(parent),
|
||||
address(p_address),
|
||||
registered(false),
|
||||
subscribers(new Map()),
|
||||
dispatcher(0),
|
||||
server(0),
|
||||
subscribersCount(0),
|
||||
handlers(new HList()),
|
||||
properties(new W::Vector()),
|
||||
models(new MList())
|
||||
{
|
||||
W::Handler* subscribe = W::Handler::create(address + W::Address({u"subscribe"}), this, &M::Model::_h_subscribe);
|
||||
W::Handler* unsubscribe = W::Handler::create(address + W::Address({u"unsubscribe"}), this, &M::Model::_h_unsubscribe);
|
||||
addHandler(subscribe);
|
||||
addHandler(unsubscribe);
|
||||
}
|
||||
|
||||
M::Model::~Model()
|
||||
{
|
||||
if (registered) {
|
||||
unregisterModel();
|
||||
}
|
||||
|
||||
MList::iterator itr = models->begin();
|
||||
MList::iterator end = models->end();
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
delete *itr;
|
||||
}
|
||||
|
||||
HList::iterator hItr = handlers->begin();
|
||||
HList::iterator hEnd = handlers->end();
|
||||
|
||||
for (; hItr != hEnd; ++hItr) {
|
||||
delete *hItr;
|
||||
}
|
||||
|
||||
delete subscribers;
|
||||
delete properties;
|
||||
delete handlers;
|
||||
delete models;
|
||||
}
|
||||
|
||||
void M::Model::addModel(M::Model* model)
|
||||
{
|
||||
models->push_back(model);
|
||||
connect(model, SIGNAL(serviceMessage(const QString&)), SIGNAL(serviceMessage(const QString&)));
|
||||
if (registered) {
|
||||
model->registerModel(dispatcher, server);
|
||||
}
|
||||
}
|
||||
|
||||
void M::Model::addHandler(W::Handler* handler)
|
||||
{
|
||||
handlers->push_back(handler);
|
||||
if (registered) {
|
||||
dispatcher->registerHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
void M::Model::addProperty(const W::String& value, const W::String& name)
|
||||
{
|
||||
W::Vocabulary vc;
|
||||
vc.insert(u"key", name);
|
||||
vc.insert(u"property", value);
|
||||
|
||||
properties->push(vc);
|
||||
|
||||
if (registered) {
|
||||
W::Vocabulary* nvc = new W::Vocabulary;
|
||||
nvc->insert(u"properties", *properties);
|
||||
broadcast(nvc, W::Address({u"properties"}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
W::Address M::Model::getAddress() const
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
void M::Model::registerModel(W::Dispatcher* dp, W::Server* srv)
|
||||
{
|
||||
if (registered) {
|
||||
emit serviceMessage(QString("Model ") + address.toString().c_str() + " is already registered");
|
||||
throw 1;
|
||||
} else {
|
||||
dispatcher = dp;
|
||||
server = srv;
|
||||
|
||||
MList::iterator itr = models->begin();
|
||||
MList::iterator end = models->end();
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
M::Model* model = *itr;
|
||||
model->registerModel(dispatcher, server);
|
||||
}
|
||||
|
||||
HList::iterator hItr = handlers->begin();
|
||||
HList::iterator hEnd = handlers->end();
|
||||
|
||||
for (; hItr != hEnd; ++hItr) {
|
||||
W::Handler* handler = *hItr;
|
||||
dispatcher->registerHandler(handler);
|
||||
}
|
||||
|
||||
registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
void M::Model::unregisterModel()
|
||||
{
|
||||
if (!registered) {
|
||||
emit serviceMessage(QString("Model ") + address.toString().c_str() + " is not registered");
|
||||
throw 2;
|
||||
} else {
|
||||
MList::iterator itr = models->begin();
|
||||
MList::iterator end = models->end();
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
Model* model = *itr;
|
||||
model->unregisterModel();
|
||||
}
|
||||
|
||||
HList::iterator hItr = handlers->begin();
|
||||
HList::iterator hEnd = handlers->end();
|
||||
|
||||
for (; hItr != hEnd; ++hItr) {
|
||||
W::Handler* handler = *hItr;
|
||||
dispatcher->unregisterHandler(handler);
|
||||
}
|
||||
|
||||
Map::iterator sItr = subscribers->begin();
|
||||
Map::iterator sEnd = subscribers->end();
|
||||
|
||||
for (; sItr != sEnd; ++sItr) {
|
||||
const W::Socket& socket = server->getConnection(sItr->first);
|
||||
disconnect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
||||
}
|
||||
subscribers->clear();
|
||||
subscribersCount = 0;
|
||||
|
||||
dispatcher = 0;
|
||||
server = 0;
|
||||
|
||||
registered = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void M::Model::h_subscribe(const W::Event& ev)
|
||||
{
|
||||
uint64_t id = ev.getSenderId();
|
||||
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
|
||||
const W::Address& source = static_cast<const W::Address&>(vc.at(u"source"));
|
||||
W::Vocabulary params;
|
||||
if (vc.has(u"params")) {
|
||||
params = static_cast<const W::Vocabulary&>(vc.at(u"params"));
|
||||
}
|
||||
|
||||
|
||||
Map::iterator sItr = subscribers->find(id);
|
||||
|
||||
if (sItr == subscribers->end()) {
|
||||
std::pair<Map::iterator, bool> pair = subscribers->emplace(std::make_pair(id, SMap()));
|
||||
if (!pair.second) {
|
||||
emit serviceMessage(QString("Model ") + address.toString().c_str() + ": something completely wrong happened");
|
||||
throw 3;
|
||||
}
|
||||
const W::Socket& socket = server->getConnection(id);
|
||||
connect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
||||
sItr = pair.first;
|
||||
}
|
||||
SMap::const_iterator oItr = sItr->second.find(source);
|
||||
if (oItr != sItr->second.end()) {
|
||||
emit serviceMessage(QString("Socket ") + id +
|
||||
" subscriber " + source.toString().c_str() +
|
||||
" is already subscribed to model " + source.toString().c_str());
|
||||
throw 4;
|
||||
}
|
||||
|
||||
sItr->second.insert(std::make_pair(source, params));
|
||||
++subscribersCount;
|
||||
|
||||
W::Vocabulary* nvc = new W::Vocabulary();
|
||||
nvc->insert(u"properties", *properties);
|
||||
|
||||
response(nvc, W::Address({u"properties"}), ev);
|
||||
emit serviceMessage(QString("Model ") + address.toString().c_str() + ": now has " + std::to_string(subscribersCount).c_str() + " subscribers");
|
||||
emit subscribersCountChange(subscribersCount);
|
||||
}
|
||||
|
||||
void M::Model::onSocketDisconnected()
|
||||
{
|
||||
W::Socket* socket = static_cast<W::Socket*>(sender());
|
||||
disconnect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
||||
uint64_t id = socket->getId();
|
||||
Map::iterator itr = subscribers->find(id);
|
||||
|
||||
if (itr == subscribers->end()) {
|
||||
emit serviceMessage(QString("Model ") + address.toString().c_str() +
|
||||
": socket disconnected have been handled for not subscribed id");
|
||||
throw 5;
|
||||
}
|
||||
|
||||
subscribersCount -= itr->second.size();
|
||||
subscribers->erase(itr);
|
||||
|
||||
emit serviceMessage(QString("Model ") + address.toString().c_str() + ": now has " + std::to_string(subscribersCount).c_str() + " subscribers");
|
||||
emit subscribersCountChange(subscribersCount);
|
||||
}
|
||||
|
||||
void M::Model::h_unsubscribe(const W::Event& ev)
|
||||
{
|
||||
uint64_t id = ev.getSenderId();
|
||||
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
|
||||
const W::Address& source = static_cast<const W::Address&>(vc.at(u"source"));
|
||||
|
||||
Map::iterator itr = subscribers->find(id);
|
||||
if (itr == subscribers->end()) {
|
||||
emit serviceMessage(QString("Socket ") + id +
|
||||
" has no subscribed addresses to model " + source.toString().c_str());
|
||||
throw 6;
|
||||
}
|
||||
|
||||
SMap& smap = itr->second;
|
||||
SMap::const_iterator sItr = smap.find(source);
|
||||
if (sItr == smap.end()) {
|
||||
emit serviceMessage(QString("Socket ") + id +
|
||||
" subscriber " + source.toString().c_str() +
|
||||
" is not subscribed to model " + source.toString().c_str());
|
||||
throw 7;
|
||||
}
|
||||
|
||||
smap.erase(sItr);
|
||||
if (smap.size() == 0) {
|
||||
const W::Socket& socket = server->getConnection(itr->first);
|
||||
disconnect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
||||
subscribers->erase(itr);
|
||||
}
|
||||
--subscribersCount;
|
||||
|
||||
emit serviceMessage(QString("Model ") + address.toString().c_str() + ": now has " + std::to_string(subscribersCount).c_str() + " subscribers");
|
||||
emit subscribersCountChange(subscribersCount);
|
||||
}
|
||||
|
||||
void M::Model::send(W::Vocabulary* vc, const W::Address& destination, uint64_t connectionId)
|
||||
{
|
||||
if (!registered) {
|
||||
emit serviceMessage(QString("An attempt to send event from model ") + address.toString().c_str() + " which was not registered");
|
||||
throw 8;
|
||||
}
|
||||
W::Event ev(destination, vc);
|
||||
ev.setSenderId(connectionId);
|
||||
server->getConnection(connectionId).send(ev);
|
||||
}
|
||||
|
||||
void M::Model::response(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Event& src)
|
||||
{
|
||||
if (!registered) {
|
||||
emit serviceMessage(QString("An attempt to send event from model ") + address.toString().c_str() + " which was not registered");
|
||||
throw 8;
|
||||
}
|
||||
const W::Vocabulary& svc = static_cast<const W::Vocabulary&>(src.getData());
|
||||
const W::Address& source = static_cast<const W::Address&>(svc.at(u"source"));
|
||||
uint64_t id = src.getSenderId();
|
||||
vc->insert(u"source", address);
|
||||
|
||||
W::Event ev(source + handlerAddress, vc);
|
||||
ev.setSenderId(id);
|
||||
server->getConnection(id).send(ev);
|
||||
}
|
||||
|
||||
void M::Model::fakeResponse(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Address& sourceAddress, const W::Event& src)
|
||||
{
|
||||
if (!registered) {
|
||||
emit serviceMessage(QString("An attempt to send event from model ") + address.toString().c_str() + " which was not registered");
|
||||
throw 8;
|
||||
}
|
||||
const W::Vocabulary& svc = static_cast<const W::Vocabulary&>(src.getData());
|
||||
const W::Address& source = static_cast<const W::Address&>(svc.at(u"source"));
|
||||
uint64_t id = src.getSenderId();
|
||||
vc->insert(u"source", sourceAddress);
|
||||
|
||||
W::Event ev(source + handlerAddress, vc);
|
||||
ev.setSenderId(id);
|
||||
server->getConnection(id).send(ev);
|
||||
}
|
||||
|
||||
void M::Model::broadcast(W::Vocabulary* vc, const W::Address& handlerAddress)
|
||||
{
|
||||
if (!registered) {
|
||||
emit serviceMessage(QString("An attempt to send event from model ") + address.toString().c_str() + " which was not registered");
|
||||
throw 8;
|
||||
}
|
||||
Map::const_iterator itr = subscribers->begin();
|
||||
Map::const_iterator end = subscribers->end();
|
||||
vc->insert(u"source", address);
|
||||
|
||||
for (;itr != end; ++itr) {
|
||||
SMap::const_iterator oItr = itr->second.begin();
|
||||
SMap::const_iterator oEnd = itr->second.end();
|
||||
for (;oItr != oEnd; ++oItr) {
|
||||
W::Event ev(oItr->first + handlerAddress, vc->copy());
|
||||
ev.setSenderId(itr->first);
|
||||
server->getConnection(itr->first).send(ev);
|
||||
}
|
||||
}
|
||||
delete vc;
|
||||
}
|
||||
|
||||
void M::Model::removeHandler(W::Handler* handler)
|
||||
{
|
||||
handlers->erase(handler);
|
||||
if (registered) {
|
||||
dispatcher->unregisterHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
void M::Model::removeModel(M::Model* model)
|
||||
{
|
||||
models->erase(model);
|
||||
if (registered) {
|
||||
model->unregisterModel();
|
||||
}
|
||||
}
|
||||
|
||||
void M::Model::passToHandler(const W::Event& event) const
|
||||
{
|
||||
if (registered) {
|
||||
dispatcher->pass(event);
|
||||
} else {
|
||||
emit serviceMessage(QString("An attempt to pass event to dispatcher from unregistered model\nModel address ") + address.toString().c_str());
|
||||
}
|
||||
}
|
92
lib/wModel/model.h
Normal file
92
lib/wModel/model.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
#ifndef W_MODEL_H
|
||||
#define W_MODEL_H
|
||||
|
||||
#include <utils/defines.h>
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include <wType/address.h>
|
||||
#include <wType/vector.h>
|
||||
#include <wType/event.h>
|
||||
#include <wType/string.h>
|
||||
#include <wSocket/socket.h>
|
||||
#include <wSocket/server.h>
|
||||
#include <wDispatcher/dispatcher.h>
|
||||
#include <wDispatcher/handler.h>
|
||||
#include <wContainer/order.h>
|
||||
|
||||
namespace M {
|
||||
|
||||
class Model : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ModelType {
|
||||
string,
|
||||
list,
|
||||
vocabulary,
|
||||
catalogue,
|
||||
|
||||
attributes = 50,
|
||||
file,
|
||||
resourceCache
|
||||
};
|
||||
|
||||
Model(const W::Address p_address, QObject* parent = 0);
|
||||
//i'm not sure about copy constructor, it just doesn't make sense, because the address is the parameter which is supposed to be unique
|
||||
virtual ~Model();
|
||||
|
||||
virtual ModelType getType() const = 0;
|
||||
virtual void set(W::Object* value) = 0;
|
||||
virtual void set(const W::Object& value) = 0;
|
||||
|
||||
void addModel(M::Model* model);
|
||||
void addHandler(W::Handler* handler);
|
||||
void addProperty(const W::String& value, const W::String& name);
|
||||
W::Address getAddress() const;
|
||||
void registerModel(W::Dispatcher* dp, W::Server* srv);
|
||||
void unregisterModel();
|
||||
|
||||
void removeHandler(W::Handler* handler);
|
||||
void removeModel(M::Model* model);
|
||||
void passToHandler(const W::Event& event) const;
|
||||
|
||||
signals:
|
||||
void serviceMessage(const QString& msg) const;
|
||||
void subscribersCountChange(uint64_t count) const;
|
||||
|
||||
protected:
|
||||
typedef std::map<W::Address, W::Vocabulary> SMap;
|
||||
typedef std::map<uint64_t, SMap> Map;
|
||||
W::Address address;
|
||||
bool registered;
|
||||
Map* subscribers;
|
||||
|
||||
void send(W::Vocabulary* vc, const W::Address& destination, uint64_t connectionId);
|
||||
void response(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Event& src);
|
||||
void fakeResponse(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Address& sourceAddress, const W::Event& src);
|
||||
void broadcast(W::Vocabulary* vc, const W::Address& handlerAddress);
|
||||
|
||||
handler(subscribe)
|
||||
handler(unsubscribe)
|
||||
|
||||
private:
|
||||
typedef W::Order<W::Handler*> HList;
|
||||
typedef W::Order<M::Model*> MList;
|
||||
|
||||
W::Dispatcher* dispatcher;
|
||||
W::Server* server;
|
||||
uint64_t subscribersCount;
|
||||
HList* handlers;
|
||||
W::Vector* properties;
|
||||
MList* models;
|
||||
|
||||
private slots:
|
||||
void onSocketDisconnected();
|
||||
};
|
||||
}
|
||||
#endif // W_MODEL_H
|
||||
|
77
lib/wModel/modelstring.cpp
Normal file
77
lib/wModel/modelstring.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "modelstring.h"
|
||||
|
||||
M::String::String(const W::String& str, const W::Address& addr, QObject* parent):
|
||||
M::Model(addr, parent),
|
||||
data(new W::String(str))
|
||||
{
|
||||
addHandler(W::Handler::create(address + W::Address({u"get"}), this, &M::String::_h_get));
|
||||
}
|
||||
|
||||
M::String::String(W::String* str, const W::Address& addr, QObject* parent):
|
||||
M::Model(addr, parent),
|
||||
data(str)
|
||||
{
|
||||
}
|
||||
|
||||
M::String::~String()
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
void M::String::h_subscribe(const W::Event& ev)
|
||||
{
|
||||
M::Model::h_subscribe(ev);
|
||||
|
||||
h_get(ev);
|
||||
}
|
||||
|
||||
void M::String::h_get(const W::Event& ev)
|
||||
{
|
||||
W::Vocabulary* vc = new W::Vocabulary;
|
||||
vc->insert(u"data", *data);
|
||||
|
||||
response(vc, W::Address({u"get"}), ev);
|
||||
}
|
||||
|
||||
void M::String::set(const W::String& str)
|
||||
{
|
||||
delete data;
|
||||
data = static_cast<W::String*>(str.copy());
|
||||
|
||||
if (registered) {
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"data", str);
|
||||
|
||||
broadcast(vc, W::Address{u"get"});
|
||||
}
|
||||
}
|
||||
|
||||
void M::String::set(W::String* str)
|
||||
{
|
||||
delete data;
|
||||
data = str;
|
||||
|
||||
if (registered) {
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
vc->insert(u"data", *str);
|
||||
|
||||
broadcast(vc, W::Address{u"get"});
|
||||
}
|
||||
}
|
||||
|
||||
void M::String::set(const W::Object& value)
|
||||
{
|
||||
set(static_cast<const W::String&>(value));
|
||||
}
|
||||
|
||||
void M::String::set(W::Object* value)
|
||||
{
|
||||
set(static_cast<W::String*>(value));
|
||||
}
|
||||
|
||||
|
||||
M::Model::ModelType M::String::getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
40
lib/wModel/modelstring.h
Normal file
40
lib/wModel/modelstring.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#ifndef M_STRING_H
|
||||
#define M_STRING_H
|
||||
|
||||
#include "model.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <wType/string.h>
|
||||
#include <wType/address.h>
|
||||
|
||||
namespace M {
|
||||
|
||||
class String: public Model
|
||||
{
|
||||
public:
|
||||
String(const W::String& str, const W::Address& addr, QObject* parent = 0);
|
||||
String(W::String* str, const W::Address& addr, QObject* parent = 0);
|
||||
|
||||
~String();
|
||||
|
||||
void set(const W::Object & value) override;
|
||||
void set(W::Object * value) override;
|
||||
void set(const W::String& str);
|
||||
void set(W::String* str);
|
||||
|
||||
M::Model::ModelType getType() const override;
|
||||
static const M::Model::ModelType type = M::Model::string;
|
||||
|
||||
protected:
|
||||
void h_subscribe(const W::Event& ev);
|
||||
handler(get)
|
||||
|
||||
private:
|
||||
W::String* data;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // M_STRING_H
|
136
lib/wModel/vocabulary.cpp
Normal file
136
lib/wModel/vocabulary.cpp
Normal file
|
@ -0,0 +1,136 @@
|
|||
#include "vocabulary.h"
|
||||
|
||||
M::Vocabulary::Vocabulary(const W::Address p_address, QObject* parent):
|
||||
M::Model(p_address, parent),
|
||||
data(new W::Vocabulary())
|
||||
{
|
||||
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Vocabulary::_h_get);
|
||||
addHandler(get);
|
||||
}
|
||||
|
||||
M::Vocabulary::Vocabulary(W::Vocabulary* p_data, const W::Address p_address, QObject* parent):
|
||||
M::Model(p_address, parent),
|
||||
data(p_data)
|
||||
{
|
||||
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Vocabulary::_h_get);
|
||||
addHandler(get);
|
||||
}
|
||||
|
||||
|
||||
M::Vocabulary::~Vocabulary()
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
void M::Vocabulary::h_subscribe(const W::Event& ev)
|
||||
{
|
||||
M::Model::h_subscribe(ev);
|
||||
|
||||
h_get(ev);
|
||||
}
|
||||
|
||||
void M::Vocabulary::h_get(const W::Event& ev)
|
||||
{
|
||||
W::Vocabulary* vc = new W::Vocabulary;
|
||||
vc->insert(u"data", data->copy());
|
||||
|
||||
response(vc, W::Address({u"get"}), ev);
|
||||
}
|
||||
|
||||
void M::Vocabulary::insert(const W::String& key, const W::Object& value)
|
||||
{
|
||||
if (registered) {
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
W::Vocabulary* insert = new W::Vocabulary();
|
||||
W::Vector* erase = new W::Vector();
|
||||
|
||||
if (data->has(key)) {
|
||||
erase->push(key);
|
||||
}
|
||||
data->insert(key, value);
|
||||
insert->insert(key, value);
|
||||
|
||||
vc->insert(u"insert", insert);
|
||||
vc->insert(u"erase", erase);
|
||||
|
||||
broadcast(vc, W::Address{u"change"});
|
||||
} else {
|
||||
data->insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void M::Vocabulary::insert(const W::String& key, W::Object* value)
|
||||
{
|
||||
if (registered) {
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
W::Vocabulary* insert = new W::Vocabulary();
|
||||
W::Vector* erase = new W::Vector();
|
||||
|
||||
if (data->has(key)) {
|
||||
erase->push(key);
|
||||
}
|
||||
data->insert(key, value);
|
||||
insert->insert(key, value->copy());
|
||||
|
||||
vc->insert(u"insert", insert);
|
||||
vc->insert(u"erase", erase);
|
||||
|
||||
broadcast(vc, W::Address{u"change"});
|
||||
} else {
|
||||
data->insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void M::Vocabulary::erase(const W::String& key)
|
||||
{
|
||||
data->erase(key);
|
||||
if (registered) {
|
||||
W::Vocabulary* vc = new W::Vocabulary();
|
||||
W::Vocabulary* insert = new W::Vocabulary();
|
||||
W::Vector* erase = new W::Vector();
|
||||
|
||||
erase->push(key);
|
||||
|
||||
vc->insert(u"insert", insert);
|
||||
vc->insert(u"erase", erase);
|
||||
|
||||
broadcast(vc, W::Address{u"change"});
|
||||
}
|
||||
}
|
||||
|
||||
void M::Vocabulary::clear()
|
||||
{
|
||||
data->clear();
|
||||
|
||||
if (registered) {
|
||||
broadcast(new W::Vocabulary(), W::Address{u"clear"});
|
||||
}
|
||||
}
|
||||
|
||||
M::Model::ModelType M::Vocabulary::getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
void M::Vocabulary::set(const W::Object& value)
|
||||
{
|
||||
delete data;
|
||||
data = static_cast<W::Vocabulary*>(value.copy());
|
||||
|
||||
W::Vocabulary* vc = new W::Vocabulary;
|
||||
vc->insert(u"data", data->copy());
|
||||
|
||||
broadcast(vc, W::Address({u"get"}));
|
||||
}
|
||||
|
||||
void M::Vocabulary::set(W::Object* value)
|
||||
{
|
||||
delete data;
|
||||
data = static_cast<W::Vocabulary*>(value);
|
||||
|
||||
W::Vocabulary* vc = new W::Vocabulary;
|
||||
vc->insert(u"data", data->copy());
|
||||
|
||||
broadcast(vc, W::Address({u"get"}));
|
||||
}
|
||||
|
45
lib/wModel/vocabulary.h
Normal file
45
lib/wModel/vocabulary.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef M_VOCABULARY_H
|
||||
#define M_VOCABULARY_H
|
||||
|
||||
#include "model.h"
|
||||
|
||||
#include <wType/object.h>
|
||||
#include <wType/address.h>
|
||||
#include <wType/vocabulary.h>
|
||||
#include <wType/vector.h>
|
||||
|
||||
|
||||
namespace M {
|
||||
class ICatalogue;
|
||||
|
||||
class Vocabulary : public M::Model
|
||||
{
|
||||
friend class ICatalogue;
|
||||
public:
|
||||
Vocabulary(const W::Address p_address, QObject* parent = 0);
|
||||
Vocabulary(W::Vocabulary* p_data, const W::Address p_address, QObject* parent = 0);
|
||||
~Vocabulary();
|
||||
|
||||
void insert(const W::String& key, const W::Object& value);
|
||||
void insert(const W::String& key, W::Object* value);
|
||||
void erase(const W::String& key);
|
||||
void clear();
|
||||
|
||||
void set(const W::Object & value) override;
|
||||
void set(W::Object* value) override;
|
||||
|
||||
M::Model::ModelType getType() const override;
|
||||
static const M::Model::ModelType type = vocabulary;
|
||||
|
||||
protected:
|
||||
void h_subscribe(const W::Event & ev) override;
|
||||
|
||||
handler(get);
|
||||
|
||||
private:
|
||||
W::Vocabulary* data;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // M_VOCABULARY_H
|
Loading…
Add table
Add a link
Reference in a new issue