From 5100d91a72ebf921dac579e882507e4a7be33350 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 5 Aug 2018 00:52:16 +0300 Subject: [PATCH] initial player stuff --- corax/CMakeLists.txt | 5 +- corax/corax.cpp | 16 +-- corax/models/CMakeLists.txt | 21 ++++ corax/models/player.cpp | 121 +++++++++++++++++++++++ corax/models/player.h | 60 ++++++++++++ corax/models/proxysong.cpp | 135 ++++++++++++++++++++++++++ corax/models/proxysong.h | 47 +++++++++ lib/wController/controller.cpp | 5 + lib/wController/controller.h | 1 + lib/wDatabase/resourcecache.cpp | 2 +- lib/wModel/CMakeLists.txt | 6 +- lib/wModel/button.cpp | 113 +++++++++++++++++++++ lib/wModel/button.h | 52 ++++++++++ lib/wModel/model.cpp | 112 +++++++++++++++------ lib/wModel/model.h | 24 +++-- lib/wModel/vocabulary.h | 3 +- lib/wServerUtils/connector.cpp | 94 +++++++++++++++++- lib/wServerUtils/connector.h | 16 ++- lib/wSocket/server.cpp | 4 +- lib/wSocket/server.h | 2 +- lib/wType/object.cpp | 2 + libjs/wController/button.js | 69 +++++++++++++ libjs/wController/controller.js | 23 +++-- libjs/wController/link.js | 6 +- libjs/wModel/CMakeLists.txt | 1 + libjs/wModel/button.js | 90 +++++++++++++++++ libjs/wModel/model.js | 9 +- lorgar/css/main.css | 4 + lorgar/lib/wController/CMakeLists.txt | 1 + lorgar/main.js | 4 +- lorgar/views/CMakeLists.txt | 1 + lorgar/views/button.js | 95 ++++++++++++++++++ lorgar/views/layout.js | 4 + lorgar/views/view.js | 26 +++-- magnus/lib/wModel/CMakeLists.txt | 1 + magnus/pages/test.js | 11 +++ perturabo/CMakeLists.txt | 2 +- perturabo/perturabo.cpp | 12 +-- 38 files changed, 1107 insertions(+), 93 deletions(-) create mode 100644 corax/models/CMakeLists.txt create mode 100644 corax/models/player.cpp create mode 100644 corax/models/player.h create mode 100644 corax/models/proxysong.cpp create mode 100644 corax/models/proxysong.h create mode 100644 lib/wModel/button.cpp create mode 100644 lib/wModel/button.h create mode 100644 libjs/wController/button.js create mode 100644 libjs/wModel/button.js create mode 100644 lorgar/views/button.js diff --git a/corax/CMakeLists.txt b/corax/CMakeLists.txt index b0c6a34..a257c53 100644 --- a/corax/CMakeLists.txt +++ b/corax/CMakeLists.txt @@ -23,6 +23,7 @@ set(SOURCES ) add_executable(corax ${HEADERS} ${SOURCES}) +add_subdirectory(models) target_link_libraries(corax Qt5::Core) target_link_libraries(corax Qt5::Network) @@ -31,10 +32,10 @@ target_link_libraries(corax wSocket) target_link_libraries(corax wDispatcher) target_link_libraries(corax utils) target_link_libraries(corax wModel) -target_link_libraries(corax wController) -target_link_libraries(corax wServerUtils) target_link_libraries(corax wDatabase) target_link_libraries(corax tag) target_link_libraries(corax tools) +target_link_libraries(corax coraxModels) +target_link_libraries(corax wServerUtils) install(TARGETS corax RUNTIME DESTINATION bin) diff --git a/corax/corax.cpp b/corax/corax.cpp index 053b391..92c4145 100644 --- a/corax/corax.cpp +++ b/corax/corax.cpp @@ -90,11 +90,11 @@ void Corax::start() server->listen(8080); cout << "Registering models..." << endl; - attributes->registerModel(dispatcher, server); - commands->registerModel(dispatcher, server); + attributes->getRegistered(connector); + commands->getRegistered(connector); for (; beg != end; ++beg) { - beg->second->registerModel(dispatcher, server); + beg->second->getRegistered(connector); } cout << "Opening caches..." << endl; @@ -115,11 +115,11 @@ void Corax::stop() std::map::iterator end = caches.end(); cout << "Stopping corax..." << endl; - commands->unregisterModel(); - attributes->unregisterModel(); + commands->getUnregistered(); + attributes->getUnregistered(); for (; beg != end; ++beg) { - beg->second->unregisterModel(); + beg->second->getUnregistered(); } server->stop(); @@ -169,10 +169,10 @@ void Corax::h_parseDirectory(const W::Event& ev) if (itr != parsers.end()) { cout << "directory " << path.toString() << " is already being parsed" << endl; } else { - const W::Socket& socket = connector->getNodeSocket(W::String(u"Perturabo")); + const W::Socket* socket = connector->getNodeSocket(W::String(u"Perturabo")); ResourceCache* music = caches.at(W::String(u"music")); ResourceCache* images = caches.at(W::String(u"images")); - Parser* parser = new Parser(&socket, dispatcher, music, images); + Parser* parser = new Parser(socket, dispatcher, music, images); parsers.insert(std::make_pair(path, parser)); connect(parser, SIGNAL(serviceMessage(const QString&)), SLOT(onModelServiceMessage(const QString&))); diff --git a/corax/models/CMakeLists.txt b/corax/models/CMakeLists.txt new file mode 100644 index 0000000..fe7c92e --- /dev/null +++ b/corax/models/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.12) +project(coraxModels) + +find_package(Qt5Core REQUIRED) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +set(HEADERS + player.h + proxysong.h +) + +set(SOURCES + player.cpp + proxysong.cpp +) + +add_library(coraxModels STATIC ${HEADERS} ${SOURCES}) + +target_link_libraries(coraxModels wModel) diff --git a/corax/models/player.cpp b/corax/models/player.cpp new file mode 100644 index 0000000..9cc439f --- /dev/null +++ b/corax/models/player.cpp @@ -0,0 +1,121 @@ +#include "player.h" + +M::Player::Player(const W::Address& address, QObject* parent): + M::Model(address, parent), + controls(), + views(), + playPauseBtn(new M::Button(address + W::Address{u"play"})), + _queueView(new M::List(address + W::Address{u"queueView"})), + _queue(), + current(0) +{ + W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Player::_h_get); + W::Handler* hqueue = W::Handler::create(address + W::Address({u"queue"}), this, &M::Player::_h_queue); + addHandler(get); + addHandler(hqueue); + + playPauseBtn->setLabel(W::String(u"play")); + playPauseBtn->setEnabled(false); + connect(playPauseBtn, SIGNAL(activated()), this, SLOT(onPlayPauseBtn())); + + addModel(playPauseBtn); + addModel(_queueView); + + controls.insert(std::make_pair(playPause, playPauseBtn->getAddress())); + views.insert(std::make_pair(queue, _queueView->getAddress())); +} + +M::Player::~Player() +{ + +} + +void M::Player::set(const W::Object& value) +{ + throw 14; //what do you expect here? not implemented, and not sure it ever would be +} + +void M::Player::set(W::Object* value) +{ + set(*value); +} + +M::Model::ModelType M::Player::getType() const +{ + return M::Model::player; +} + +void M::Player::h_subscribe(const W::Event& ev) +{ + M::Model::h_subscribe(ev); + + h_get(ev); +} + + +void M::Player::h_get(const W::Event& ev) +{ + W::Vector* ctrls = new W::Vector(); + ItemMap::const_iterator citr = controls.begin(); + ItemMap::const_iterator cend = controls.end(); + + for (; citr != cend; ++citr) { + W::Vocabulary* cvc = new W::Vocabulary(); + cvc->insert(u"type", new W::Uint64(cend->first)); + cvc->insert(u"address", cend->second); + + ctrls->push(cvc); + } + + W::Vector* vws = new W::Vector(); + ItemMap::const_iterator vitr = views.begin(); + ItemMap::const_iterator vend = views.end(); + + for (; vitr != vend; ++vitr) { + W::Vocabulary* vvc = new W::Vocabulary(); + vvc->insert(u"type", new W::Uint64(vend->first)); + vvc->insert(u"address", vend->second); + + vws->push(vvc); + } + + W::Vocabulary* res = new W::Vocabulary(); + + res->insert(u"controls", ctrls); + res->insert(u"views", vws); + + response(res, W::Address({u"get"}), ev); +} + +void M::Player::onPlayPauseBtn() +{ + +} + +void M::Player::h_queue(const W::Event& ev) +{ + const W::Vocabulary& data = static_cast(ev.getData()); + + const W::Uint64& id = static_cast(data.at(u"id")); + ProxySong* song = new ProxySong(id, address + W::Address{u"currentPlayback"}); + addModel(song); + if (current == 0) { + current = song; + views.insert(std::make_pair(currentPlayback, song->getAddress())); + W::Vocabulary* avc = new W::Vocabulary(); + avc->insert(u"type", new W::Uint64(currentPlayback)); + avc->insert(u"address", song->getAddress()); + + W::Vector* add = new W::Vector(); + add->push(avc); + + W::Vocabulary* res = new W::Vocabulary(); + res->insert(u"add", add); + res->insert(u"remove", new W::Vector()); + + broadcast(res, W::Address{u"viewsChange"}); + } else { + _queue.push_back(song); + _queueView->push(song->getAddress()); + } +} diff --git a/corax/models/player.h b/corax/models/player.h new file mode 100644 index 0000000..d2b17a9 --- /dev/null +++ b/corax/models/player.h @@ -0,0 +1,60 @@ +#ifndef PLAYER_H +#define PLAYER_H + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "proxysong.h" +/** + * @todo write docs + */ +namespace M { + class Player : public M::Model { + Q_OBJECT + public: + Player(const W::Address& address, QObject* parent = 0); + ~Player(); + + void set(const W::Object & value) override; + void set(W::Object * value) override; + M::Model::ModelType getType() const override; + + enum ItemType { + playPause, + currentPlayback, + queue + }; + + protected: + void h_subscribe(const W::Event & ev) override; + + handler(get); + handler(queue); + + private: + typedef std::map ItemMap; + typedef std::deque Queue; + + ItemMap controls; + ItemMap views; + M::Button* playPauseBtn; + M::List* _queueView; + Queue _queue; + ProxySong* current; + + private slots: + void onPlayPauseBtn(); + + }; +} + +#endif // PLAYER_H diff --git a/corax/models/proxysong.cpp b/corax/models/proxysong.cpp new file mode 100644 index 0000000..8e742b8 --- /dev/null +++ b/corax/models/proxysong.cpp @@ -0,0 +1,135 @@ +#include "proxysong.h" + +ProxySong::ProxySong(const W::Uint64& p_id, const W::Address& p_address, QObject* parent): + M::Vocabulary(p_address, parent), + songCtrl(new C::Vocabulary(W::Address{u"songs", W::String(p_id.toString())})), + albumCtrl(0), + artistCtrl(0), + fileId(0), + _ready(false) +{ + addController(songCtrl, W::String(u"Perturabo")); + connect(songCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), SLOT(onSongNewElement(const W::String&, const W::Object&))); + connect(songCtrl, SIGNAL(removeElement(const W::String&)), SLOT(onSongRemoveElement(const W::String&))); + + insert(W::String(u"id"), p_id); + insert(W::String(u"artist"), new W::String(u"undefined")); + insert(W::String(u"album"), new W::String(u"undefined")); + insert(W::String(u"name"), new W::String(u"undefined")); + insert(W::String(u"image"), new W::Uint64(0)); +} + +bool ProxySong::isReady() const +{ + return _ready; +} + +ProxySong::~ProxySong() +{ +} + +void ProxySong::onSongNewElement(const W::String& key, const W::Object& element) +{ + if (key == u"name") { + insert(key, element); + } else if (key == u"audio") { + if (_ready) { + _ready = false; + emit notReady(); + } + + fileId = static_cast(element); + _ready = true; + emit ready(); + } else if (key == u"artist") { + if (artistCtrl != 0) { + removeController(artistCtrl); + disconnect(artistCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), this, SLOT(onArtistNewElement(const W::String&, const W::Object&))); + disconnect(artistCtrl, SIGNAL(removeElement(const W::String&)), this, SLOT(onAtristRemoveElement(const W::String&))); + artistCtrl->deleteLater(); + } + const W::Uint64& aid = static_cast(element); + artistCtrl = new C::Vocabulary(W::Address{u"artists", W::String(aid.toString())}); + addController(artistCtrl, W::String(u"Perturabo")); + connect(artistCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), SLOT(onArtistNewElement(const W::String&, const W::Object&))); + connect(artistCtrl, SIGNAL(removeElement(const W::String&)), SLOT(onAtristRemoveElement(const W::String&))); + } else if (key == u"album") { + if (albumCtrl != 0) { + removeController(albumCtrl); + disconnect(albumCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), this, SLOT(onAlbumNewElement(const W::String&, const W::Object&))); + disconnect(albumCtrl, SIGNAL(removeElement(const W::String&)), this, SLOT(onAlbumRemoveElement(const W::String&))); + albumCtrl->deleteLater(); + } + const W::Uint64& aid = static_cast(element); + albumCtrl = new C::Vocabulary(W::Address{u"albums", W::String(aid.toString())}); + addController(albumCtrl, W::String(u"Perturabo")); + connect(albumCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), SLOT(onAlbumNewElement(const W::String&, const W::Object&))); + connect(albumCtrl, SIGNAL(removeElement(const W::String&)), SLOT(onAlbumRemoveElement(const W::String&))); + } +} + +void ProxySong::onSongRemoveElement(const W::String& key) +{ + if (key == u"name") { + insert(key, new W::String(u"undefined")); + } else if (key == u"audio") { + if (_ready) { + _ready = false; + fileId = W::Uint64(0); + emit notReady(); + } + } else if (key == u"artist") { + if (artistCtrl != 0) { + removeController(artistCtrl); + disconnect(artistCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), this, SLOT(onArtistNewElement(const W::String&, const W::Object&))); + disconnect(artistCtrl, SIGNAL(removeElement(const W::String&)), this, SLOT(onAtristRemoveElement(const W::String&))); + artistCtrl->deleteLater(); + artistCtrl = 0; + } + } else if (key == u"album") { + if (albumCtrl != 0) { + removeController(albumCtrl); + disconnect(albumCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), this, SLOT(onAlbumNewElement(const W::String&, const W::Object&))); + disconnect(albumCtrl, SIGNAL(removeElement(const W::String&)), this, SLOT(onAlbumRemoveElement(const W::String&))); + albumCtrl->deleteLater(); + albumCtrl = 0; + } + } +} + +void ProxySong::onAlbumNewElement(const W::String& key, const W::Object& element) +{ + if (key == u"name") { + insert(W::String(u"album"), element); + } else if (key == u"image") { + insert(key, element); + } +} + +void ProxySong::onAlbumRemoveElement(const W::String& key) +{ + if (key == u"name") { + insert(W::String(u"album"), new W::String(u"undefined")); + } else if (key == u"image") { + insert(key, new W::Uint64(0)); + } +} + +void ProxySong::onArtistNewElement(const W::String& key, const W::Object& element) +{ + if (key == u"name") { + insert(W::String(u"artist"), element); + } +} + +void ProxySong::onArtistRemoveElement(const W::String& key) +{ + if (key == u"name") { + insert(W::String(u"artist"), new W::String(u"undefined")); + } +} + +const W::Uint64 & ProxySong::getFileId() const +{ + return fileId; +} diff --git a/corax/models/proxysong.h b/corax/models/proxysong.h new file mode 100644 index 0000000..48aba44 --- /dev/null +++ b/corax/models/proxysong.h @@ -0,0 +1,47 @@ +#ifndef PROXYSONG_H +#define PROXYSONG_H + +/** + * @todo write docs + */ +#include +#include + +#include + +#include + +class ProxySong : public M::Vocabulary { + Q_OBJECT +public: + ProxySong(const W::Uint64& p_id, const W::Address& p_address, QObject* parent = 0); + ~ProxySong(); + + const W::Uint64& getFileId() const; + bool isReady() const; + +signals: + void ready(); + void notReady(); + +private: + C::Vocabulary* songCtrl; + C::Vocabulary* albumCtrl; + C::Vocabulary* artistCtrl; + + W::Uint64 fileId; + bool _ready; + +private slots: + void onSongNewElement(const W::String& key, const W::Object& element); + void onSongRemoveElement(const W::String& key); + + void onAlbumNewElement(const W::String& key, const W::Object& element); + void onAlbumRemoveElement(const W::String& key); + + void onArtistNewElement(const W::String& key, const W::Object& element); + void onArtistRemoveElement(const W::String& key); + +}; + +#endif // PROXYSONG_H diff --git a/lib/wController/controller.cpp b/lib/wController/controller.cpp index 5fe4572..6ac7c61 100644 --- a/lib/wController/controller.cpp +++ b/lib/wController/controller.cpp @@ -276,3 +276,8 @@ bool C::Controller::isSubscribed() { return subscribed; } + +const W::Address & C::Controller::getAddress() const +{ + return address; +} diff --git a/lib/wController/controller.h b/lib/wController/controller.h index 1749093..7372a2d 100644 --- a/lib/wController/controller.h +++ b/lib/wController/controller.h @@ -40,6 +40,7 @@ namespace C { void subscribe(); void unsubscribe(); bool isSubscribed(); + const W::Address& getAddress() const; void removeHandler(W::Handler* handler); void removeController(C::Controller* ctrl); diff --git a/lib/wDatabase/resourcecache.cpp b/lib/wDatabase/resourcecache.cpp index 64d383b..14014d6 100644 --- a/lib/wDatabase/resourcecache.cpp +++ b/lib/wDatabase/resourcecache.cpp @@ -215,7 +215,7 @@ void ResourceCache::h_subscribeMember(const W::Event& ev) M::File* modelRecord = M::File::create(readFile(*record), address + lastHops >> 1); delete record; addModel(modelRecord); - passToHandler(ev); + passToLocalHandler(ev); } catch (int err) { if (err == 3) { emit serviceMessage(QString("An attempt to create and subscribe record model in resourcecache, but it is not found. Event: ") + ev.toString().c_str()); diff --git a/lib/wModel/CMakeLists.txt b/lib/wModel/CMakeLists.txt index cd37fb7..fb70a7b 100644 --- a/lib/wModel/CMakeLists.txt +++ b/lib/wModel/CMakeLists.txt @@ -14,6 +14,7 @@ set(HEADERS attributes.h icatalogue.h catalogue.h + button.h file/file.h ) @@ -25,12 +26,13 @@ set(SOURCES attributes.cpp icatalogue.cpp catalogue.cpp + button.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 wServerUtils) target_link_libraries(wModel wType) +target_link_libraries(wModel wController) diff --git a/lib/wModel/button.cpp b/lib/wModel/button.cpp new file mode 100644 index 0000000..16d103e --- /dev/null +++ b/lib/wModel/button.cpp @@ -0,0 +1,113 @@ +#include "button.h" + +M::Button::Button(const W::Address& address, QObject* parent): + M::Model(address, parent), + enabled(true), + hasImage(false), + hasLabel(false), + imageName(0), + label(0) +{ + W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Button::_h_get); + W::Handler* activate = W::Handler::create(address + W::Address({u"activate"}), this, &M::Button::_h_activate); + + addHandler(get); + addHandler(activate); +} + +M::Button::~Button() +{ + if (hasImage) { + delete imageName; + } +} + +void M::Button::setImage(const W::String& p_image) +{ + + if (hasImage) { + if (*imageName != p_image) { + imageName = static_cast(p_image.copy()); + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"image", p_image); + broadcast(vc, W::Address{u"changeImage"}); + } + } else { + imageName = static_cast(p_image.copy()); + hasImage = true; + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"image", p_image); + broadcast(vc, W::Address{u"setImage"}); + } + hasImage = true; +} + +void M::Button::setEnabled(bool p_enabled) +{ + if (enabled != p_enabled) { + enabled = p_enabled; + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"enable", new W::Boolean(enabled)); + broadcast(vc, W::Address{u"setEnabled"}); + } +} + +void M::Button::setLabel(const W::String& p_label) +{ + if (hasLabel) { + label->set(p_label); + } else { + label = new M::String(p_label, address + W::Address{u"label"}); + addModel(label); + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"hasLabel", new W::Boolean(true)); + vc->insert(u"label", label->getAddress()); + broadcast(vc, W::Address{u"setLabel"}); + hasLabel = true; + } +} + +void M::Button::h_subscribe(const W::Event& ev) +{ + M::Model::h_subscribe(ev); + + h_get(ev); +} + +void M::Button::h_get(const W::Event& ev) +{ + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"hasImage", new W::Boolean(hasImage)); + if (hasImage) { + vc->insert(u"image", imageName->copy()); + } + vc->insert(u"hasLabel", new W::Boolean(hasLabel)); + if (hasLabel) { + vc->insert(u"label", label->getAddress()); + } + vc->insert(u"enabled", new W::Boolean(enabled)); + + response(vc, W::Address({u"get"}), ev); +} + +void M::Button::h_activate(const W::Event& ev) +{ + if (enabled) { + emit activated(); + } +} + +M::Model::ModelType M::Button::getType() const +{ + return M::Model::button; +} + +void M::Button::set(const W::Object& value) +{ + throw 14; //what do you expect here? not implemented, and not sure it ever would be +} + +void M::Button::set(W::Object* value) +{ + set(*value); +} diff --git a/lib/wModel/button.h b/lib/wModel/button.h new file mode 100644 index 0000000..d73046d --- /dev/null +++ b/lib/wModel/button.h @@ -0,0 +1,52 @@ +#ifndef BUTTON_H +#define BUTTON_H + +#include +#include + +#include + +#include +#include +#include +#include + +/** + * @todo write docs + */ +namespace M { + class Button : public Model { + Q_OBJECT + public: + Button(const W::Address& address, QObject* parent = 0); + ~Button(); + + void setImage(const W::String& p_image); + void setLabel(const W::String& p_label); + void setEnabled(bool p_enabled); + + M::Model::ModelType getType() const override; + void set(const W::Object & value) override; + void set(W::Object * value) override; + + signals: + void activated() const; + + protected: + void h_subscribe(const W::Event & ev) override; + + handler(get); + handler(activate); + + protected: + bool enabled; + bool hasImage; + bool hasLabel; + + W::String* imageName; + M::String* label; + }; +} + + +#endif // BUTTON_H diff --git a/lib/wModel/model.cpp b/lib/wModel/model.cpp index d1168cd..dc1522e 100644 --- a/lib/wModel/model.cpp +++ b/lib/wModel/model.cpp @@ -5,12 +5,12 @@ M::Model::Model(const W::Address p_address, QObject* parent): address(p_address), registered(false), subscribers(new Map()), - dispatcher(0), - server(0), + connector(0), subscribersCount(0), handlers(new HList()), properties(new W::Vector()), - models(new MList()) + models(new MList()), + controllers(new Controllers()) { 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); @@ -21,7 +21,7 @@ M::Model::Model(const W::Address p_address, QObject* parent): M::Model::~Model() { if (registered) { - unregisterModel(); + getUnregistered(); } MList::iterator itr = models->begin(); @@ -37,11 +37,19 @@ M::Model::~Model() for (; hItr != hEnd; ++hItr) { delete *hItr; } + + Controllers::iterator cItr = controllers->begin(); + Controllers::iterator cEnd = controllers->end(); + + for (; cItr != cEnd; ++cItr) { + delete cItr->first; + } delete subscribers; delete properties; delete handlers; delete models; + delete controllers; } void M::Model::addModel(M::Model* model) @@ -49,7 +57,7 @@ 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); + model->getRegistered(connector); } } @@ -57,7 +65,7 @@ void M::Model::addHandler(W::Handler* handler) { handlers->push_back(handler); if (registered) { - dispatcher->registerHandler(handler); + connector->registerHandler(handler); } } @@ -83,21 +91,20 @@ W::Address M::Model::getAddress() const } -void M::Model::registerModel(W::Dispatcher* dp, W::Server* srv) +void M::Model::getRegistered(U::Connector* cn) { if (registered) { emit serviceMessage(QString("Model ") + address.toString().c_str() + " is already registered"); throw 1; } else { - dispatcher = dp; - server = srv; + connector = cn; MList::iterator itr = models->begin(); MList::iterator end = models->end(); for (; itr != end; ++itr) { M::Model* model = *itr; - model->registerModel(dispatcher, server); + model->getRegistered(connector); } HList::iterator hItr = handlers->begin(); @@ -105,14 +112,21 @@ void M::Model::registerModel(W::Dispatcher* dp, W::Server* srv) for (; hItr != hEnd; ++hItr) { W::Handler* handler = *hItr; - dispatcher->registerHandler(handler); + connector->registerHandler(handler); + } + + Controllers::iterator cItr = controllers->begin(); + Controllers::iterator cEnd = controllers->end(); + + for (; cItr != cEnd; ++cItr) { + connector->registerController(cItr->first, cItr->second); } registered = true; } } -void M::Model::unregisterModel() +void M::Model::getUnregistered() { if (!registered) { emit serviceMessage(QString("Model ") + address.toString().c_str() + " is not registered"); @@ -123,7 +137,7 @@ void M::Model::unregisterModel() for (; itr != end; ++itr) { Model* model = *itr; - model->unregisterModel(); + model->getUnregistered(); } HList::iterator hItr = handlers->begin(); @@ -131,21 +145,27 @@ void M::Model::unregisterModel() for (; hItr != hEnd; ++hItr) { W::Handler* handler = *hItr; - dispatcher->unregisterHandler(handler); + connector->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())); + const W::Socket* socket = connector->getConnection(sItr->first); + disconnect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); } subscribers->clear(); subscribersCount = 0; - dispatcher = 0; - server = 0; + Controllers::iterator cItr = controllers->begin(); + Controllers::iterator cEnd = controllers->end(); + + for (; cItr != cEnd; ++cItr) { + connector->unregisterController(cItr->first, cItr->second); + } + + connector = 0; registered = false; } @@ -162,7 +182,6 @@ void M::Model::h_subscribe(const W::Event& ev) params = static_cast(vc.at(u"params")); } - Map::iterator sItr = subscribers->find(id); if (sItr == subscribers->end()) { @@ -171,8 +190,8 @@ void M::Model::h_subscribe(const W::Event& ev) 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())); + const W::Socket* socket = connector->getConnection(id); + connect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); sItr = pair.first; } SMap::const_iterator oItr = sItr->second.find(source); @@ -238,8 +257,8 @@ void M::Model::h_unsubscribe(const W::Event& ev) smap.erase(sItr); if (smap.size() == 0) { - const W::Socket& socket = server->getConnection(itr->first); - disconnect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); + const W::Socket* socket = connector->getConnection(itr->first); + disconnect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); subscribers->erase(itr); } --subscribersCount; @@ -256,7 +275,7 @@ void M::Model::send(W::Vocabulary* vc, const W::Address& destination, uint64_t c } W::Event ev(destination, vc); ev.setSenderId(connectionId); - server->getConnection(connectionId).send(ev); + connector->getConnection(connectionId)->send(ev); } void M::Model::response(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Event& src) @@ -272,7 +291,7 @@ void M::Model::response(W::Vocabulary* vc, const W::Address& handlerAddress, con W::Event ev(source + handlerAddress, vc); ev.setSenderId(id); - server->getConnection(id).send(ev); + connector->getConnection(id)->send(ev); } void M::Model::fakeResponse(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Address& sourceAddress, const W::Event& src) @@ -288,7 +307,7 @@ void M::Model::fakeResponse(W::Vocabulary* vc, const W::Address& handlerAddress, W::Event ev(source + handlerAddress, vc); ev.setSenderId(id); - server->getConnection(id).send(ev); + connector->getConnection(id)->send(ev); } void M::Model::broadcast(W::Vocabulary* vc, const W::Address& handlerAddress) @@ -307,7 +326,7 @@ void M::Model::broadcast(W::Vocabulary* vc, const W::Address& handlerAddress) for (;oItr != oEnd; ++oItr) { W::Event ev(oItr->first + handlerAddress, vc->copy()); ev.setSenderId(itr->first); - server->getConnection(itr->first).send(ev); + connector->getConnection(itr->first)->send(ev); } } delete vc; @@ -317,23 +336,54 @@ void M::Model::removeHandler(W::Handler* handler) { handlers->erase(handler); if (registered) { - dispatcher->unregisterHandler(handler); + connector->unregisterHandler(handler); } } void M::Model::removeModel(M::Model* model) { models->erase(model); + disconnect(model, SIGNAL(serviceMessage(const QString&)), this, SIGNAL(serviceMessage(const QString&))); if (registered) { - model->unregisterModel(); + model->getUnregistered(); } } -void M::Model::passToHandler(const W::Event& event) const +void M::Model::passToLocalHandler(const W::Event& event) const { if (registered) { - dispatcher->pass(event); + connector->passThroughDispatcher(event); } else { emit serviceMessage(QString("An attempt to pass event to dispatcher from unregistered model\nModel address ") + address.toString().c_str()); } } + +void M::Model::addController(C::Controller* ctrl, const W::String& nodeName) +{ + Controllers::const_iterator itr = controllers->find(ctrl); + if (itr != controllers->end()) { + emit serviceMessage(QString("An attempt to add controller ") + ctrl->getAddress().toString().c_str() + QString(" for the second time in model ") + address.toString().c_str()); + throw 9; + } + controllers->insert(std::make_pair(ctrl, nodeName)); + connect(ctrl, SIGNAL(serviceMessage(const QString&)), SIGNAL(serviceMessage(const QString&))); + if (registered) { + connector->registerController(ctrl, nodeName);; + } +} + +void M::Model::removeController(C::Controller* ctrl) +{ + Controllers::const_iterator itr = controllers->find(ctrl); + if (itr == controllers->end()) { + emit serviceMessage(QString("An attempt to remove absent controller ") + ctrl->getAddress().toString().c_str() + QString(" from the model ") + address.toString().c_str()); + throw 10; + } + + disconnect(ctrl, SIGNAL(serviceMessage(const QString&)), this, SIGNAL(serviceMessage(const QString&))); + if (registered) { + connector->unregisterController(itr->first, itr->second); + } + controllers->erase(itr); +} + diff --git a/lib/wModel/model.h b/lib/wModel/model.h index 8b44fc9..c10b173 100644 --- a/lib/wModel/model.h +++ b/lib/wModel/model.h @@ -13,10 +13,10 @@ #include #include #include -#include -#include #include #include +#include +#include namespace M { @@ -29,10 +29,15 @@ namespace M { list, vocabulary, catalogue, + image, + button, + model, attributes = 50, file, - resourceCache + resourceCache, + + player = 107 }; Model(const W::Address p_address, QObject* parent = 0); @@ -46,13 +51,15 @@ namespace M { void addModel(M::Model* model); void addHandler(W::Handler* handler); void addProperty(const W::String& value, const W::String& name); + void addController(C::Controller* ctrl, const W::String& nodeName); W::Address getAddress() const; - void registerModel(W::Dispatcher* dp, W::Server* srv); - void unregisterModel(); + void getRegistered(U::Connector* connector); + void getUnregistered(); void removeHandler(W::Handler* handler); void removeModel(M::Model* model); - void passToHandler(const W::Event& event) const; + void removeController(C::Controller* ctrl); + void passToLocalHandler(const W::Event& event) const; signals: void serviceMessage(const QString& msg) const; @@ -76,13 +83,14 @@ namespace M { private: typedef W::Order HList; typedef W::Order MList; + typedef std::map Controllers; - W::Dispatcher* dispatcher; - W::Server* server; + U::Connector* connector; uint64_t subscribersCount; HList* handlers; W::Vector* properties; MList* models; + Controllers* controllers; private slots: void onSocketDisconnected(); diff --git a/lib/wModel/vocabulary.h b/lib/wModel/vocabulary.h index 5ddb250..bcbb08d 100644 --- a/lib/wModel/vocabulary.h +++ b/lib/wModel/vocabulary.h @@ -12,8 +12,7 @@ namespace M { class ICatalogue; - class Vocabulary : public M::Model - { + class Vocabulary : public M::Model { friend class ICatalogue; public: Vocabulary(const W::Address p_address, QObject* parent = 0); diff --git a/lib/wServerUtils/connector.cpp b/lib/wServerUtils/connector.cpp index 77b1211..724df6e 100644 --- a/lib/wServerUtils/connector.cpp +++ b/lib/wServerUtils/connector.cpp @@ -1,4 +1,5 @@ #include "connector.h" +#include "commands.h" U::Connector::Connector(W::Dispatcher* dp, W::Server* srv, U::Commands* cmds, QObject* parent): QObject(parent), @@ -6,7 +7,8 @@ U::Connector::Connector(W::Dispatcher* dp, W::Server* srv, U::Commands* cmds, QO server(srv), commands(cmds), nodes(), - ignoredNodes() + ignoredNodes(), + controllers() { connect(server, SIGNAL(newConnection(const W::Socket&)), SLOT(onNewConnection(const W::Socket&))); connect(server, SIGNAL(closedConnection(const W::Socket&)), SLOT(onClosedConnection(const W::Socket&))); @@ -30,6 +32,17 @@ U::Connector::~Connector() for (; itr != end; ++itr) { commands->removeCommand(dc + itr->first); } + + std::multimap::const_iterator cbeg = controllers.begin(); + std::multimap::const_iterator cend = controllers.end(); + + for (; cbeg != cend; ++cbeg) { + C::Controller* ctrl = cbeg->second; + if (ctrl->isSubscribed()) { + ctrl->unsubscribe(); + ctrl->unregisterController(); + } + } } void U::Connector::addIgnoredNode(const W::String& name) @@ -43,7 +56,7 @@ void U::Connector::sendTo(const W::String& name, const W::Event& event) if (itr != nodes.end()) { throw new NodeAccessError(name); } else { - server->getConnection(itr->second).send(event); + server->getConnection(itr->second)->send(event); } } @@ -69,6 +82,14 @@ void U::Connector::onNewConnection(const W::Socket& socket) emit serviceMessage(QString("New connection, id: ") + socket.getId().toString().c_str()); connect(&socket, SIGNAL(message(const W::Event&)), dispatcher, SLOT(pass(const W::Event&))); + std::multimap::const_iterator beg = controllers.lower_bound(name); + std::multimap::const_iterator end = controllers.upper_bound(name); + + for (; beg != end; ++beg) { + beg->second->registerController(dispatcher, &socket); + beg->second->subscribe(); + } + emit nodeConnected(name); } } else { @@ -90,6 +111,14 @@ void U::Connector::onClosedConnection(const W::Socket& socket) if (ign == ignoredNodes.end()) { Map::const_iterator itr = nodes.find(name); if (itr != nodes.end()) { + std::multimap::const_iterator beg = controllers.lower_bound(name); + std::multimap::const_iterator end = controllers.upper_bound(name); + + for (; beg != end; ++beg) { + beg->second->unsubscribe(); + beg->second->unregisterController(); + } + emit nodeDisconnected(name); commands->removeCommand(W::String(u"disconnect") + name); nodes.erase(itr); @@ -114,7 +143,7 @@ void U::Connector::h_disconnect(const W::Event& ev) server->closeConnection(itr->second); } -const W::Socket& U::Connector::getNodeSocket(const W::String& name) +const W::Socket* U::Connector::getNodeSocket(const W::String& name) { Map::const_iterator itr = nodes.find(name); if (itr == nodes.end()) { @@ -122,3 +151,62 @@ const W::Socket& U::Connector::getNodeSocket(const W::String& name) } return server->getConnection(itr->second); } + +void U::Connector::registerHandler(W::Handler* handler) +{ + dispatcher->registerHandler(handler); +} + +void U::Connector::unregisterHandler(W::Handler* handler) +{ + dispatcher->unregisterHandler(handler); +} + +const W::Socket * U::Connector::getConnection(uint64_t p_id) const +{ + return server->getConnection(p_id); +} + +void U::Connector::passThroughDispatcher(const W::Event& ev) const +{ + dispatcher->pass(ev); +} + +void U::Connector::registerController(C::Controller* ctrl, const W::String& node) +{ + std::set::const_iterator iitr = ignoredNodes.find(node); + if (iitr != ignoredNodes.end()) { + throw 3; //this means you're trying to receive something from one of ignored nodes, which never going to be handled in connector, most probably it's a mistake + } + controllers.insert(std::make_pair(node, ctrl)); + Map::const_iterator itr = nodes.find(node); + if (itr != nodes.end()) { + ctrl->registerController(dispatcher, server->getConnection(itr->second)); + ctrl->subscribe(); //let's say I always need them subscribed, for now at least + } +} + +void U::Connector::unregisterController(C::Controller* ctrl, const W::String& node) +{ + bool found = false; + std::multimap::const_iterator beg = controllers.lower_bound(node); + std::multimap::const_iterator end = controllers.upper_bound(node); + + for (; beg != end; ++beg) { + if (beg->second == ctrl) { + found = true; //TODO make a proper way to store 'em + break; + } + } + + if (!found) { + throw 4; + } + + if (ctrl->isSubscribed()) { + ctrl->unsubscribe(); + ctrl->unregisterController(); + } + controllers.erase(beg); +} + diff --git a/lib/wServerUtils/connector.h b/lib/wServerUtils/connector.h index 4ba0a48..e6ff2f8 100644 --- a/lib/wServerUtils/connector.h +++ b/lib/wServerUtils/connector.h @@ -1,11 +1,14 @@ #ifndef CONNECTOR_H #define CONNECTOR_H +#include + #include #include #include #include +#include #include #include @@ -16,9 +19,11 @@ #include -#include "commands.h" +#include namespace U { + class Commands; + class Connector : public QObject { Q_OBJECT @@ -29,7 +34,13 @@ namespace U { void addIgnoredNode(const W::String& name); void sendTo(const W::String& name, const W::Event& event); - const W::Socket& getNodeSocket(const W::String& name); + const W::Socket* getNodeSocket(const W::String& name); + void registerHandler(W::Handler* handler); + void unregisterHandler(W::Handler* handler); + const W::Socket* getConnection(uint64_t p_id) const; + void passThroughDispatcher(const W::Event& ev) const; + void registerController(C::Controller* ctrl, const W::String& node); + void unregisterController(C::Controller* ctrl, const W::String& node); signals: void serviceMessage(const QString& msg); @@ -42,6 +53,7 @@ namespace U { U::Commands* commands; Map nodes; std::set ignoredNodes; + std::multimap controllers; protected: handler(connect); diff --git a/lib/wSocket/server.cpp b/lib/wSocket/server.cpp index ec44bc3..9b7f6ad 100644 --- a/lib/wSocket/server.cpp +++ b/lib/wSocket/server.cpp @@ -44,14 +44,14 @@ void W::Server::stop() } } -const W::Socket& W::Server::getConnection(uint64_t p_id) const +const W::Socket* W::Server::getConnection(uint64_t p_id) const { std::map::const_iterator itr = connections.find(p_id); if (itr == connections.end()) { throw new SocketAccessError(); } - return *(itr->second); + return itr->second; } uint64_t W::Server::getConnectionsCount() const diff --git a/lib/wSocket/server.h b/lib/wSocket/server.h index 7981a71..eeeb7b1 100644 --- a/lib/wSocket/server.h +++ b/lib/wSocket/server.h @@ -27,7 +27,7 @@ namespace W void listen(uint16_t port); void stop(); - const Socket& getConnection(uint64_t p_id) const; + const Socket* getConnection(uint64_t p_id) const; uint64_t getConnectionsCount() const; void closeConnection(uint64_t p_id); void openConnection(const String& addr, const Uint64& port); diff --git a/lib/wType/object.cpp b/lib/wType/object.cpp index d567867..40507ec 100644 --- a/lib/wType/object.cpp +++ b/lib/wType/object.cpp @@ -102,5 +102,7 @@ W::Object::StdStr W::Object::getTypeName(W::Object::objectType type) case blob: return "Blob"; } + + throw 5; } diff --git a/libjs/wController/button.js b/libjs/wController/button.js new file mode 100644 index 0000000..e98534c --- /dev/null +++ b/libjs/wController/button.js @@ -0,0 +1,69 @@ +"use strict"; + +var Controller = require("./controller"); +var String = require("./string"); +var Vocabulary = require("../wType/vocabulary"); + +var Button = Controller.inherit({ + "className": "Button", + "constructor": function(addr) { + Controller.fn.constructor.call(this, addr); + + this.enabled = false; + this.hasLabel = false; + + this.addHandler("get"); + this.addHandler("setLabel"); + this.addHandler("setImage"); + this.addHandler("setEnabled"); + this.addHandler("changeImage"); + }, + "destructor": function() { + + Controller.fn.destructor.call(this); + }, + "activate": function() { + if (this.enabled) { + this.send(new Vocabulary, "activate"); + } + }, + "_h_changeImage": function(ev) { + + }, + "_h_get": function(ev) { + this._h_setLabel(ev); + this._h_setImage(ev); + this._h_setEnabled(ev); + }, + "_h_setEnabled": function(ev) { + var data = ev.getData(); + + var enabled = data.at("enabled").valueOf(); + if (this.enabled !== enabled) { + this.enabled = enabled; + this.trigger("setEnabled", this.enabled); + } + }, + "_h_setLabel": function(ev) { + var data = ev.getData(); + var hasLabel = data.at("hasLabel").valueOf(); + + if (hasLabel !== this.hasLabel) { + this.hasLabel = hasLabel; + if (hasLabel) { + this.label = new String(data.at("label").clone()); + this.addController(this.label); + this.trigger("setLabel", true, this.label); + } else { + this.trigger("setLabel", false); + this.removeController(this.label); + this.label.destructor(); + } + } + }, + "_h_setImage": function(ev) { + + } +}); + +module.exports = Button; diff --git a/libjs/wController/controller.js b/libjs/wController/controller.js index ece32b7..268f67d 100644 --- a/libjs/wController/controller.js +++ b/libjs/wController/controller.js @@ -328,8 +328,10 @@ Controller.ModelType = { String: 0, List: 1, Vocabulary: 2, - Image: 3, - Controller: 4, + Catalogue: 3, + Image: 4, + Button: 5, + Controller: 6, Attributes: 50, @@ -339,15 +341,18 @@ Controller.ModelType = { PageStorage: 103, PanesList: 104, Theme: 105, - ThemeStorage: 106 + ThemeStorage: 106, + Player: 107 }; Controller.ReversedModelType = { "0": "String", "1": "List", "2": "Vocabulary", - "3": "Image", - "4": "Controller", + "3": "Catalogue", + "4": "Image", + "5": "Button", + "6": "Controller", "50": "Attributes", @@ -357,7 +362,8 @@ Controller.ReversedModelType = { "103": "PageStorage", "104": "PanesList", "105": "Theme", - "106": "ThemeStorage" + "106": "ThemeStorage", + "107": "Player" }; Controller.ModelTypesPaths = { @@ -372,7 +378,10 @@ Controller.ModelTypesPaths = { PanesList: "./panesList", //resolve as dependency Theme: "./theme", //resolve as dependency ThemeStorage: "./themeStorage", //resolve as dependency - Image: "./image" //resolve as dependency + Image: "./image", //resolve as dependency + Button: "./button", //resolve as dependency + Catalogue: "./catalogue", //resolve as dependency + Player: "./player" //resolve as dependency }; Controller.constructors = { diff --git a/libjs/wController/link.js b/libjs/wController/link.js index 1ba0ee2..2babdb3 100644 --- a/libjs/wController/link.js +++ b/libjs/wController/link.js @@ -10,16 +10,12 @@ var Link = Controller.inherit({ "constructor": function(addr) { Controller.fn.constructor.call(this, addr); - var hop = new Address(["label"]); - this.targetAddress = new Address([]); this.label = new String(addr['+'](hop)); this.addController(this.label); this.addHandler("get"); - - hop.destructor(); }, "destructor": function() { this.targetAddress.destructor(); @@ -35,4 +31,6 @@ var Link = Controller.inherit({ } }); +var hop = new Address(["label"]); + module.exports = Link; diff --git a/libjs/wModel/CMakeLists.txt b/libjs/wModel/CMakeLists.txt index b06a09c..d0bd7cc 100644 --- a/libjs/wModel/CMakeLists.txt +++ b/libjs/wModel/CMakeLists.txt @@ -13,5 +13,6 @@ configure_file(themeStorage.js themeStorage.js) configure_file(vocabulary.js vocabulary.js) configure_file(attributes.js attributes.js) configure_file(image.js image.js) +configure_file(button.js button.js) add_subdirectory(proxy) diff --git a/libjs/wModel/button.js b/libjs/wModel/button.js new file mode 100644 index 0000000..276f51f --- /dev/null +++ b/libjs/wModel/button.js @@ -0,0 +1,90 @@ +"use strict"; + +var Model = require("./model"); +var ModelString = require("./string"); + +var Vocabulary = require("../wType/vocabulary"); +var Boolean = require("../wType/boolean"); +var Address = require("../wType/address"); +var String = require("../wType/string"); + +var Button = Model.inherit({ + "className": "Button", + "constructor": function(address) { + Model.fn.constructor.call(this, address); + + this._enabled = true; + this._hasImage = false; + this._hasLabel =false; + this._imageName = undefined; + this._label = undefined; + + this.addHandler("get"); + this.addHandler("activate"); + }, + "setImage": function(name) { + if (this._hasImage) { + if (this._imageName !== name) { + this._image = name; + var vc = new Vocabulary(); + vc.insert("image", new String(this._imageName)); + this.broadcast(vc, "changeImage"); + } + } else { + this._image = name; + this._hasImage = true; + var vc = new Vocabulary(); + vc.insert("image", new String(this._imageName)); + this.broadcast(vc, "setImage"); + } + }, + "setEnabled": function(enabled) { + if (enabled !== this._enabled) { + this._enabled = enabled; + var vc = new Vocabulary(); + vc.insert("enabled", new Boolean(this._enabled)); + this.broadcast(vc, "setEnabled"); + } + }, + "setLabel": function(text) { + if (this._hasLabel) { + this._label.set(text); + } else { + this._label = new ModelString(this._address["+"](labelHop), text); + this.addModel(this._label); + var vc = new Vocabulary(); + vc.insert("hasLabel", new Boolean(true)); + vc.insert("label", this._label.getAddress()); + this.broadcast(vc, "setLabel"); + this._hasLabel = true; + } + }, + "_h_subscribe": function(ev) { + Model.fn._h_subscribe.call(this, ev); + + this._h_get(ev); + }, + "_h_get": function(ev) { + var vc = new Vocabulary(); + vc.insert("hasImage", new Boolean(this._hasImage)); + if (this._hasImage) { + vc.insert("image", new String(this._imageName)); + } + vc.insert("hasLabel", new Boolean(this._hasLabel)); + if (this._hasLabel) { + vc.insert("label", this._label.getAddress()); + } + vc.insert("enabled", new Boolean(this._enabled)); + + this.response(vc, "get", ev); + }, + "_h_activate": function() { + if (this._enabled) { + this.trigger("activated"); + } + } +}); + +var labelHop = new Address(["label"]); + +module.exports = Button; diff --git a/libjs/wModel/model.js b/libjs/wModel/model.js index d5f68a1..e5643b5 100644 --- a/libjs/wModel/model.js +++ b/libjs/wModel/model.js @@ -299,8 +299,10 @@ Model.ModelType = { String: 0, List: 1, Vocabulary: 2, - Image: 3, - Model: 4, + //Catalogue: 3, + Image: 4, + Button: 5, + Model: 6, Attributes: 50, @@ -310,7 +312,8 @@ Model.ModelType = { PageStorage: 103, PanesList: 104, Theme: 105, - ThemeStorage: 106 + ThemeStorage: 106, + Player: 107 }; module.exports = Model; diff --git a/lorgar/css/main.css b/lorgar/css/main.css index 4a92774..26e4c65 100644 --- a/lorgar/css/main.css +++ b/lorgar/css/main.css @@ -45,3 +45,7 @@ div.dragging .draggable { cursor: -moz-grabbing; cursor: grabbing; } + +.disabled { + opacity: 0.7; +} diff --git a/lorgar/lib/wController/CMakeLists.txt b/lorgar/lib/wController/CMakeLists.txt index 79ca778..c758a1e 100644 --- a/lorgar/lib/wController/CMakeLists.txt +++ b/lorgar/lib/wController/CMakeLists.txt @@ -17,3 +17,4 @@ add_jslib(wController/localModel.js lib/wController/localModel ${LORGAR_DIR} bro add_jslib(wController/imagePane.js lib/wController/imagePane ${LORGAR_DIR} browser) add_jslib(wController/file/file.js lib/wController/file/file ${LORGAR_DIR} browser) add_jslib(wController/image.js lib/wController/image ${LORGAR_DIR} browser) +add_jslib(wController/button.js lib/wController/button ${LORGAR_DIR} browser) diff --git a/lorgar/main.js b/lorgar/main.js index 286a597..e5aa4fc 100644 --- a/lorgar/main.js +++ b/lorgar/main.js @@ -36,8 +36,8 @@ } } - Controller.initialize(["String", "List", "Vocabulary", "Page", "PanesList", "Link", "Image"], waiter.check.bind(waiter, "controllers")); - View.initialize(["Label", "Page", "PanesList", "Nav", "Image"], waiter.check.bind(waiter, "views")); + Controller.initialize(["String", "List", "Vocabulary", "Page", "PanesList", "Link", "Image", "Button"], waiter.check.bind(waiter, "controllers")); + View.initialize(["Label", "Page", "PanesList", "Nav", "Image", "Button"], waiter.check.bind(waiter, "views")); var test = new Test(); test.run(); diff --git a/lorgar/views/CMakeLists.txt b/lorgar/views/CMakeLists.txt index c656448..2a4393b 100644 --- a/lorgar/views/CMakeLists.txt +++ b/lorgar/views/CMakeLists.txt @@ -11,5 +11,6 @@ configure_file(mainLayout.js mainLayout.js) configure_file(page.js page.js) configure_file(pane.js pane.js) configure_file(image.js image.js) +configure_file(button.js button.js) add_subdirectory(helpers) diff --git a/lorgar/views/button.js b/lorgar/views/button.js new file mode 100644 index 0000000..7dbeaf5 --- /dev/null +++ b/lorgar/views/button.js @@ -0,0 +1,95 @@ +"use strict"; +(function() { + var moduleName = "views/button"; + + var deps = []; + deps.push("views/layout"); + deps.push("views/label"); + + define(moduleName, deps, function() { + var Layout = require("views/layout"); + var Label = require("views/label"); + + var Button = Layout.inherit({ + "className": "Button", + "constructor": function(controller, options) { + var base = { + padding: 5 + }; + W.extend(base, options) + Layout.fn.constructor.call(this, controller, base); + + this.addClass("hoverable"); + this._enabled = true; + this._hasLabel = false; + this._e.addEventListener("click", this._onClick.bind(this), false); + + controller.on("setEnabled", this._onSetEnabled, this); + controller.on("setLabel", this._onSetLabel, this); + }, + "destructor": function() { + this._f.off("setEnabled", this._onSetEnabled, this); + this._f.off("setLabel", this._onSetLabel, this); + + Layout.fn.destructor.call(this); + }, + "append": function(child, aligment, index) { + this._updateLimits(); + + Layout.fn.append.call(this, child, aligment, index); + }, + "_onChildChangeLimits": function(child) { + this._updateLimits(); + + Layout.fn._onChildChangeLimits.call(this, child); + }, + "_onClick": function() { + if (this._enabled) { + this._f.activate(); + } + }, + "_onSetEnabled": function(enabled) { + if (this._enabled !== enabled) { + this._enabled = enabled; + if (this._enabled) { + this.addClass("hoverable"); + this.removeClass("disabled"); + } else { + this.removeClass("hoverable"); + this.addClass("disabled"); + } + } + }, + "_onSetLabel": function(hasLabel, label) { + if (this._hasLabel !== hasLabel) { + this._hasLabel = hasLabel; + if (this._hasLabel) { + this._label = new Label(label); + this.append(this._label, Layout.Aligment.CenterCenter); + } else { + this._label.destructor(); + delete this._label(); + } + } + }, + "_updateLimits": function() { + var minWidth = this._o.padding * 2; + var maxWidth = this._o.padding * 2; + var minHeight = this._o.padding * 2; + var maxHeight = this._o.padding * 2; + + if (this._hasLabel) { + minWidth += this._label._o.minWidth; + minHeight += this._label._o.minHeight; + maxWidth += this._label._o.maxWidth; + maxHeight += this._label._o.maxHeight; + } + + this._setLimits(minWidth, minHeight, maxWidth, maxHeight); + } + }); + + return Button; + }) +})(); + diff --git a/lorgar/views/layout.js b/lorgar/views/layout.js index c54feba..f41c45c 100644 --- a/lorgar/views/layout.js +++ b/lorgar/views/layout.js @@ -76,8 +76,12 @@ } } + if (this._w !== undefined && this._h !== undefined) { child.setSize(this._w, this._h); + index = index || this._c.length - 1; + var c = this._c[index]; + this._positionElement(c); } }, "clear": function() { diff --git a/lorgar/views/view.js b/lorgar/views/view.js index efe9125..ba4231f 100644 --- a/lorgar/views/view.js +++ b/lorgar/views/view.js @@ -191,9 +191,12 @@ } if (needToTell) { this.trigger("changeLimits", this); + if (this._w !== undefined && this._h !== undefined) { + this.setSize(this._w, this._h); + } } - return needToTell && this._events.changeLimits && this._events.changeLimits.length; //to see if someone actually going to listen that event + return needToTell && this._events.changeLimits && this._events.changeLimits.length; //to see if someone actually going to listen that event, if not - return result }, "setMaxSize": function(w, h) { this._o.maxWidth = w; @@ -284,22 +287,27 @@ View.ViewType = { Label: 0, - Image: 3, - View: 4, + Image: 4, + Button: 5, + View: 6, Page: 102, - PanesList: 104 + PanesList: 104, + Player: 107 }; View.ReversedViewType = { "0": "Label", - "3": "Image", - "4": "View", + "4": "Image", + "5": "Button", + "6": "View", "101": "Nav", "102": "Page", - "104": "PanesList" + "104": "PanesList", + + "107": "Player" }; View.ViewTypesPaths = { @@ -307,7 +315,9 @@ Nav: "views/nav", Page: "views/page", PanesList: "views/panesList", - Image: "views/image" + Image: "views/image", + Button: "views/button", + Player: "views/player" }; View.constructors = { diff --git a/magnus/lib/wModel/CMakeLists.txt b/magnus/lib/wModel/CMakeLists.txt index 01c6b6a..fdff702 100644 --- a/magnus/lib/wModel/CMakeLists.txt +++ b/magnus/lib/wModel/CMakeLists.txt @@ -13,5 +13,6 @@ add_jslib(wModel/themeStorage.js lib/wModel/themeStorage ${MAGNUS_DIR} node) add_jslib(wModel/vocabulary.js lib/wModel/vocabulary ${MAGNUS_DIR} node) add_jslib(wModel/attributes.js lib/wModel/attributes ${MAGNUS_DIR} node) add_jslib(wModel/image.js lib/wModel/image ${MAGNUS_DIR} node) +add_jslib(wModel/button.js lib/wModel/button ${MAGNUS_DIR} node) add_subdirectory(proxy) diff --git a/magnus/pages/test.js b/magnus/pages/test.js index 584493e..99fa73f 100644 --- a/magnus/pages/test.js +++ b/magnus/pages/test.js @@ -2,6 +2,7 @@ var Page = require("../lib/wModel/page"); var String = require("../lib/wModel/string"); +var Button = require("../lib/wModel/button"); var Address = require("../lib/wType/address"); @@ -13,6 +14,16 @@ var TestPage = Page.inherit({ var header = new String(this._address["+"](new Address(["message"])), "This is a test page"); header.addProperty("fontFamily", "casualFont"); this.addItem(header, 0, 0, 1, 1, Page.Aligment.CenterTop); + + this._button = new Button(this._address["+"](new Address(["testButton"]))); + this._button.setLabel("Push me"); + this._button.on("activated", this._onActivate, this); + this.addItem(this._button, 1, 0, 1, 1, Page.Aligment.CenterTop); + }, + "_onActivate": function() { + this.trigger("serviceMessage", "Button works!"); + this._button.setEnabled(false); + setTimeout(this._button.setEnabled.bind(this._button, true), 3000); } }); diff --git a/perturabo/CMakeLists.txt b/perturabo/CMakeLists.txt index 82b4d97..c37ac4f 100644 --- a/perturabo/CMakeLists.txt +++ b/perturabo/CMakeLists.txt @@ -25,7 +25,7 @@ target_link_libraries(perturabo wSocket) target_link_libraries(perturabo wDispatcher) target_link_libraries(perturabo utils) target_link_libraries(perturabo wModel) -target_link_libraries(perturabo wServerUtils) target_link_libraries(perturabo wDatabase) +target_link_libraries(perturabo wServerUtils) install(TARGETS perturabo RUNTIME DESTINATION bin) diff --git a/perturabo/perturabo.cpp b/perturabo/perturabo.cpp index 4d5917d..7231262 100644 --- a/perturabo/perturabo.cpp +++ b/perturabo/perturabo.cpp @@ -86,11 +86,11 @@ void Perturabo::start() server->listen(8082); cout << "Registering models..." << endl; - attributes->registerModel(dispatcher, server); - commands->registerModel(dispatcher, server); + attributes->getRegistered(connector); + commands->getRegistered(connector); for (; beg != end; ++beg) { - beg->second->registerModel(dispatcher, server); + beg->second->getRegistered(connector); } cout << "Opening and indexing databases..." << endl; @@ -115,11 +115,11 @@ void Perturabo::stop() commands->enableCommand(W::String(u"clearDatabase"), false); for (; beg != end; ++beg) { - beg->second->unregisterModel(); + beg->second->getUnregistered(); } - commands->unregisterModel(); - attributes->unregisterModel(); + commands->getUnregistered(); + attributes->getUnregistered(); server->stop(); }