Commit 75b68d99 authored by Leander Schulten's avatar Leander Schulten
Browse files

Remove bug prone logic of the IDBase class. Now the class does not manages...

Remove bug prone logic of the IDBase class. Now the class does not manages automatically all objects instances of the subclasses which has caused many problems. Now the Models are managed in a ModelManager singleton and for some classes the centralized model management gets removed(e.g. now the Program owns the DevicePrograms). The ModelVector is now the only QAbstractItemModel subclass. All other subclasses gets replaced by the ModelVector class.
parent 30f3dab6
......@@ -29,10 +29,10 @@ bool saveData(QFile &file){
return true;
}
template<typename Subclass>
void saveIDBaseObjects(QJsonObject &o,QString entryName ){
template<typename Vector>
void saveIDBaseObjects(QJsonObject &o,const Vector & vector, QString entryName ){
QJsonArray array;
for(const auto p : IDBase<Subclass>::getAllIDBases()){
for(const auto & p : vector){
QJsonObject o;
p->writeJsonObject(o);
array.append(o);
......@@ -43,11 +43,11 @@ void saveIDBaseObjects(QJsonObject &o,QString entryName ){
QByteArray saveData(){
qDebug()<<"SAVE DATA";
QJsonObject o;
saveIDBaseObjects<DMX::DevicePrototype>(o,"DevicePrototypes");
saveIDBaseObjects<DMX::Device>(o,"Devices");
saveIDBaseObjects<DMX::ProgrammPrototype>(o,"ProgrammPrototypes");
saveIDBaseObjects<DMX::Programm>(o,"Programms");
saveIDBaseObjects<User>(o,"Users");
saveIDBaseObjects(o,ModelManager::get().getDevicePrototypes(),"DevicePrototypes");
saveIDBaseObjects(o,ModelManager::get().getDevices(),"Devices");
saveIDBaseObjects(o,ModelManager::get().getProgramPrototypes(),"ProgrammPrototypes");
saveIDBaseObjects(o,ModelManager::get().getPrograms(),"Programms");
saveIDBaseObjects(o,UserManagment::get()->getUsers(),"Users");
o.insert("password",QString::fromLatin1(password.toBase64()));
{
QJsonObject u;
......@@ -73,13 +73,6 @@ QByteArray saveData(){
return QJsonDocument(o).toJson();
}
template<typename Subclass>
void loadIDBaseObjects(const QJsonObject &o,QString entryName ){
for(const auto e : o[entryName].toArray()){
new Subclass(e.toObject());
}
}
std::function<void()> loadData(QFile &file){
if(!file.open(QIODevice::ReadOnly)){
return [](){qDebug()<<"Error: can not open file";};
......@@ -92,10 +85,18 @@ std::function<void()> loadData(QFile &file){
std::function<void()> loadData(QByteArray data){
const auto o = QJsonDocument::fromJson(data).object();
loadIDBaseObjects<DMX::DevicePrototype>(o,"DevicePrototypes");
loadIDBaseObjects<DMX::Device>(o,"Devices");
loadIDBaseObjects<DMX::ProgrammPrototype>(o,"ProgrammPrototypes");
loadIDBaseObjects<DMX::Programm>(o,"Programms");
for(const auto e : o["DevicePrototypes"].toArray()){
ModelManager::get().addNewDevicePrototype(e.toObject());
}
for(const auto e : o["Devices"].toArray()){
ModelManager::get().addNewDevice(e.toObject());
}
for(const auto e : o["ProgrammPrototypes"].toArray()){
ModelManager::get().addNewProgramPrototype(e.toObject());
}
for(const auto e : o["Programms"].toArray()){
ModelManager::get().addNewProgram(e.toObject());
}
password = QByteArray::fromBase64(o["password"].toString().toLatin1());
{//USERS
for(const auto e : o["Users"].toArray()){
......
......@@ -108,7 +108,11 @@ bool CodeCompletions::filterAcceptsRow(int sourceRow,
{
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
CodeCompletionEntry* data = sourceModel()->data(index).value<CodeCompletionEntry*>();
return data->completion.contains(this->filterRegExp());
if(data) {
return data->completion.contains(this->filterRegExp());
} else {
return false;
}
}
......
#include "device.h"
#include <QJsonArray>
#include <QQmlEngine>
#include <modelmanager.h>
namespace DMX{
Device::Device(const QJsonObject &o):NamedObject(o),IDBase<Device>(o),
prototype(IDBase<DevicePrototype>::getIDBaseObjectByID(o["prototype"])),
prototype(ModelManager::get().getDevicePrototypeById(o["prototype"])),
startDMXChannel(o["startDMXChannel"].toInt()),
position(o["position"].toObject()["x"].toInt(),o["position"].toObject()["y"].toInt()){
if(prototype==nullptr){
std::cerr << "Availible Device Prototypes : ";
for(const auto & r : IDBase<DevicePrototype>::getAllIDBases()){
for(const auto & r : ModelManager::get().getDevicePrototypes()){
std::cerr << r->getID().value()<<' ';
}
std::cerr << "Search for Device Prototype with ID : " << o["prototype"].toString().toLongLong();
......@@ -21,7 +23,7 @@ Device::Device(const QJsonObject &o):NamedObject(o),IDBase<Device>(o),
const auto id = f["channel"].toString().toLongLong();
for(auto i = getChannels().cbegin();i!=getChannels().cend();++i){
if((**i).getID()==id){
this->filter.emplace_back(*i,new DMXChannelFilter(f["filter"].toObject()));
this->filter.emplace_back(i->get(),std::make_unique<DMXChannelFilter>(f["filter"].toObject()));
break;
}
}
......@@ -38,7 +40,7 @@ void Device::writeJsonObject(QJsonObject &o) const{
o.insert("position",position);
o.insert("startDMXChannel",static_cast<int>(startDMXChannel));
QJsonArray filter;
for(const auto f : this->filter){
for(const auto & f : this->filter){
QJsonObject o;
o.insert("channel",QString::number(f.first->getID().value()));
QJsonObject fil;
......@@ -52,7 +54,6 @@ void Device::writeJsonObject(QJsonObject &o) const{
void Device::channelRemoved(Channel *c){
for(auto i = filter.cbegin();i!=filter.cend();++i){
if(i->first==c){
delete i->second;
filter.erase(i);
return;
}
......@@ -60,25 +61,25 @@ void Device::channelRemoved(Channel *c){
}
void Device::channelAdded(Channel *c){
filter.emplace_back(c,new DMXChannelFilter());
filter.emplace_back(c,std::make_unique<DMXChannelFilter>());
}
DMXChannelFilter * Device::getFilterForChannel( Channel *c){
for(auto i = filter.cbegin();i!=filter.cend();++i){
if(i->first==c){
QQmlEngine::setObjectOwnership(i->second,QQmlEngine::CppOwnership);
return i->second;
QQmlEngine::setObjectOwnership(i->second.get(),QQmlEngine::CppOwnership);
return i->second.get();
}
}
filter.emplace_back(c,new DMXChannelFilter);
QQmlEngine::setObjectOwnership(filter.back().second,QQmlEngine::CppOwnership);
return filter.back().second;
filter.emplace_back(c,std::make_unique<DMXChannelFilter>());
QQmlEngine::setObjectOwnership(filter.back().second.get(),QQmlEngine::CppOwnership);
return filter.back().second.get();
}
DMXChannelFilter * Device::getFilterForChannelindex(int index){
for(auto i = getChannels().cbegin();i!=getChannels().cend();++i){
if((**i).getIndex()==index){
return getFilterForChannel(*i);
return getFilterForChannel(i->get());
}
}
return nullptr;
......
......@@ -35,7 +35,7 @@ protected:
/**
* @brief filter Für jeden Channel einen Filter, der einen Default Value setzt und endergebnisse des Programms filtert;
*/
std::vector<std::pair<Channel*,DMXChannelFilter*>> filter;
std::vector<std::pair<Channel*,std::unique_ptr<DMXChannelFilter>>> filter;
private slots:
void channelRemoved(Channel *);
void channelAdded(Channel *);
......@@ -45,7 +45,7 @@ public:
Device(DevicePrototype * prototype, int startDMXChannel, QString name, QString desciption="",QPoint position = QPoint(-1,-1)):NamedObject(name,desciption),prototype(prototype),startDMXChannel(startDMXChannel),position(position){
connect(prototype,&DevicePrototype::channelAdded,this,&Device::channelAdded);
for(auto i = prototype->getChannels().cbegin();i != prototype->getChannels().cend();++i){
filter.emplace_back(*i,new DMXChannelFilter);
filter.emplace_back(i->get(),std::make_unique<DMXChannelFilter>());
}
}
......@@ -57,9 +57,9 @@ public:
unsigned int getStartDMXChannel()const{return startDMXChannel;}
Q_SLOT void setStartDMXChannel(unsigned int newStart){if(newStart == startDMXChannel)return;startDMXChannel = newStart; emit startDMXChannelChanged(startDMXChannel);}
const std::vector<Channel*> & getChannels()const{return prototype->getChannels();}
const std::vector<std::unique_ptr<Channel>> & getChannels()const{return prototype->getChannels();}
const std::vector<std::pair<Channel*,DMXChannelFilter*>> & getChannelFilter()const{return filter;}
const std::vector<std::pair<Channel*,std::unique_ptr<DMXChannelFilter>>> & getChannelFilter()const{return filter;}
Q_INVOKABLE DMXChannelFilter * getFilterForChannel( Channel * c);
Q_INVOKABLE DMXChannelFilter * getFilterForChannelindex(int intdex);
......
......@@ -3,20 +3,6 @@
namespace DMX{
void ChannelVector::beginPushBack(int length){
beginInsertRows(QModelIndex(),channels.size(),channels.size()+length);
}
void ChannelVector::endPushBack(){
endInsertRows();
}
void ChannelVector::pop_back(){
const auto pos = channels.size()-1;
beginRemoveRows(QModelIndex(),pos,pos);
channels.pop_back();
endRemoveRows();
}
void DevicePrototype::removeChannels(int newMaxIndex){
if (newMaxIndex<0||newMaxIndex>getNumberOfChannels()) {
......@@ -24,9 +10,8 @@ void DevicePrototype::removeChannels(int newMaxIndex){
}
// Elemente ganz hinten löschen
for (int i = 0; i < getNumberOfChannels() - newMaxIndex; ++i) {
channelRemoved(channels.getChannel().back());
delete channels.getChannel().back();
channels.pop_back();
channelRemoved(channels.getVector().back().get());
channels.erase(std::next(channels.begin(),static_cast<int>(channels.size())-1));
}
}
......@@ -36,52 +21,52 @@ void DevicePrototype::addChannel(int channel, QString name, QString description)
if (channel>=getNumberOfChannels()) {
channels.beginPushBack(getNumberOfChannels()-channel);
for (int i = getNumberOfChannels(); i < channel; ++i) {
channels.getChannel().push_back(new Channel(i));
emit channelAdded(channels.getChannel().back());
channels.push_back(std::make_unique<Channel>(i));
emit channelAdded(channels.getVector().back().get());
QJsonObject o;
channels.getChannel().back()->writeJsonObject(o);
channels.back()->writeJsonObject(o);
}
channels.getChannel().push_back(new Channel(channel,name,description));
channels.getVector().push_back(std::make_unique<Channel>(channel,name,description));
channels.endPushBack();
emit channelAdded(channels.getChannel().back());
emit channelAdded(channels.getVector().back().get());
QJsonObject o;
channels.getChannel().back()->writeJsonObject(o);
channels.getVector().back()->writeJsonObject(o);
}else{
// eigenschaften setzten
channels.getChannel()[channel]->setName(name);
channels.getChannel()[channel]->setDescription(description);
channels.getVector()[channel]->setName(name);
channels.getVector()[channel]->setDescription(description);
}
}
const Channel * DevicePrototype::getChannelById(const int id) const{
for(auto c = channels.getChannel().cbegin();c!=channels.getChannel().cend();++c){
const Channel * DevicePrototype::getChannelById(const ID::value_type id) const{
for(auto c = channels.getVector().cbegin();c!=channels.getVector().cend();++c){
if ((**c).getID().value() == id) {
return *c;
return c->get();
}
}
return nullptr;
}
const Channel * DevicePrototype::getChannelByName(const QString &name) const{
for(auto c = channels.getChannel().cbegin();c!=channels.getChannel().cend();++c){
for(auto c = channels.getVector().cbegin();c!=channels.getVector().cend();++c){
if ((**c).getName() == name) {
return *c;
return c->get();
}
}
return nullptr;
}
const Channel * DevicePrototype::getChannelByIndex(const unsigned int channelIndex) const{
if (channelIndex>=channels.getChannel().size()) {
if (channelIndex>=channels.getVector().size()) {
return nullptr;
}
return channels.getChannel()[channelIndex];
return channels.getVector()[channelIndex].get();
}
DevicePrototype::DevicePrototype(const QJsonObject &o):NamedObject(o),IDBase(o){
auto array = o["channels"].toArray();
for(const auto c : array){
channels.getChannel().push_back(new Channel(c.toObject()));
channels.push_back(std::make_unique<Channel>(c.toObject()));
}
}
......@@ -89,7 +74,7 @@ void DevicePrototype::writeJsonObject(QJsonObject &o) const{
NamedObject::writeJsonObject(o);
IDBase::writeJsonObject(o);
QJsonArray channels;
for(const auto c : this->channels.getChannel()){
for(const auto & c : this->channels.getVector()){
QJsonObject o;
c->writeJsonObject(o);
channels.append(o);
......
......@@ -6,63 +6,15 @@
#include <QVector>
#include "channel.h"
#include "idbase.h"
#include <QAbstractListModel>
#include <QDebug>
#include <memory>
#include "modelvector.h"
namespace DMX{
class ChannelVector : public QAbstractListModel{
std::vector<Channel*> channels;
public:
enum{
NameRole = Qt::UserRole+1,IndexRole,DescriptionRole
};
const std::vector<Channel*>& getChannel()const{return channels;}
std::vector<Channel*>& getChannel(){return channels;}
virtual int rowCount(const QModelIndex &) const override{return static_cast<int>(channels.size());}
virtual QVariant data(const QModelIndex &index, int role) const override{
if(index.row()>=0&&index.row()<int(channels.size())){
switch(role){
case Qt::DisplayRole:
case NameRole:
return channels[index.row()]->getName();
case Qt::ToolTipRole:
case DescriptionRole:
return channels[index.row()]->getDescription();
case IndexRole:
return channels[index.row()]->getIndex();
}
return QVariant::fromValue(channels[index.row()]);
}
qDebug()<<"index out\n";
return QVariant();
}
virtual bool setData(const QModelIndex &index, const QVariant &value, int role) override{
if(index.row()>=0&&index.row()<int(channels.size())){
switch(role){
case Qt::DisplayRole:
case NameRole:
channels[index.row()]->setName(value.toString());
break;
case Qt::ToolTipRole:
case DescriptionRole:
channels[index.row()]->setDescription(value.toString());
break;
default:
return false;
}
return true;
}
return false;
}
QHash<int,QByteArray> roleNames()const override{
QHash<int,QByteArray> r;
r[NameRole] = "name";
r[IndexRole] = "index";
r[DescriptionRole] = "description";
return r;
}
void pop_back();
void beginPushBack(int length);
void endPushBack();
class ChannelVector : public ModelVector<std::unique_ptr<Channel>>{
Q_OBJECT
};
/** Jedes Gerät(Scanner/Laser/Lampe/...) bekommt ein Device Prototype, wo festgelegt wird, auf welchem Channel welche Daten anliegen
......@@ -81,7 +33,7 @@ private:
public:
DevicePrototype(const QJsonObject &o);
DevicePrototype(QString name, QString description=""):NamedObject(name,description){}
int getNumberOfChannels()const{return static_cast<int>(channels.getChannel().size());}
int getNumberOfChannels()const{return static_cast<int>(channels.getVector().size());}
/**
* @brief removeChannels Entfernt Channel bis zu einem bestimmten Index
* @param newMaxIndex Der neue Maximale Index (Inclusiv)
......@@ -101,10 +53,10 @@ public:
void addChannel(int channel, QString name, QString description="");
const Channel * getChannelByName(const QString &name)const;
const Channel * getChannelById(const int id)const;
const Channel * getChannelById(const ID::value_type id)const;
const Channel * getChannelByIndex(const unsigned int channelIndex)const;
const std::vector<Channel*> & getChannels()const{return channels.getChannel();}
const std::vector<std::unique_ptr<Channel>> & getChannels()const{return channels.getVector();}
void writeJsonObject(QJsonObject &o)const;
......
#include "dmxchannelfilter.h"
#include "programm.h"
#include "device.h"
#include "modelmanager.h"
namespace DMX{
......@@ -71,8 +72,8 @@ void DMXChannelFilter::initValue(unsigned char *value){
}
void DMXChannelFilter::initValues(unsigned char *values, unsigned int numberOfChannels){
for(const auto d : IDBase<Device>::getAllIDBases()){
for(const auto f : d->getChannelFilter()){
for(const auto & d : ModelManager::get().getDevices()){
for(const auto & f : d->getChannelFilter()){
const auto index = d->getStartDMXChannel()+f.first->getIndex();
if(index<numberOfChannels){
f.second->initValue(values+index);
......@@ -82,8 +83,8 @@ void DMXChannelFilter::initValues(unsigned char *values, unsigned int numberOfCh
}
void DMXChannelFilter::filterValues(unsigned char *values, unsigned int numberOfChannels){
for(const auto d : IDBase<Device>::getAllIDBases()){
for(const auto f : d->getChannelFilter()){
for(const auto & d : ModelManager::get().getDevices()){
for(const auto & f : d->getChannelFilter()){
const auto index = d->getStartDMXChannel()+f.first->getIndex();
if(index<numberOfChannels){
f.second->filterValue(values+index);
......
......@@ -7,6 +7,7 @@
#include <QDir>
#include <cstring>
#include "modules/dmxconsumer.h"
#include <QQmlEngine>
//#define LOG_DRIVER
......
#include "programm.h"
#include <QJsonArray>
#include <unordered_set>
#include "modelmanager.h"
namespace DMX{
......@@ -41,13 +42,14 @@ Programm::Programm(const QJsonObject &o):NamedObject(o),IDBase<Programm>(o),spee
}
void Programm::addDeviceProgramm(const QJsonObject &o){
programms.push_back(new DeviceProgramm(IDBase<Device>::getIDBaseObjectByID(o["device"]),
IDBase<ProgrammPrototype>::getIDBaseObjectByID(o["programmPrototype"]),
programms.push_back(std::make_unique<DeviceProgramm>(ModelManager::get().getDeviceById(o["device"]),
ModelManager::get().getProgramPrototypeById(o["programmPrototype"]),
o["offset"].toDouble()));
emit deviceProgrammAdded(programms.back());
connect(programms.back(),&DeviceProgramm::destroyed,this,&Programm::deviceProgrammDeleted);
emit deviceProgrammAdded(programms.back().get());
}
void Programm::writeJsonObject(QJsonObject &o) const{
NamedObject::writeJsonObject(o);
IDBase<Programm>::writeJsonObject(o);
......@@ -71,23 +73,23 @@ std::map<Programm*,std::map<Device*,std::vector<Channel*>>> Programm::run(){
return std::map<Programm*,std::map<Device*,std::vector<Channel*>>>();
}
std::unordered_set<int> newUsedChannels;
for(const auto p : this->programms){
for(const auto cp : p->getProgrammPrototyp()->getChannelProgramms()){
for(const auto & p : this->programms){
for(const auto & cp : p->getProgrammPrototyp()->getChannelProgramms()){
const auto channelNummer = p->device->getStartDMXChannel() + cp->channel->getIndex();
newUsedChannels.insert(channelNummer);
}
}
std::map<Programm*,std::map<Device*,std::vector<Channel*>>> map;
for(const auto p : Programm::getAllIDBases()){
for(const auto & p : ModelManager::get().getPrograms()){
if(p->isRunning()){
//für jedes Device Programm
for(auto dp_ = p->programms.cbegin();dp_!=p->programms.cend();++dp_){
auto dp = *dp_;
auto & dp = *dp_;
//für jedes Channel Programm
for(const auto cp : dp->getProgrammPrototyp()->getChannelProgramms()){
for(const auto & cp : dp->getProgrammPrototyp()->getChannelProgramms()){
const auto channelNummer = dp->device->getStartDMXChannel() + cp->channel->getIndex();
if(newUsedChannels.find(channelNummer)!=newUsedChannels.end()){
map[p][dp->getDevice()].push_back(cp->getChannel());
map[p.get()][dp->getDevice()].push_back(cp->getChannel());
}
}
}
......@@ -100,13 +102,13 @@ std::map<Programm*,std::map<Device*,std::vector<Channel*>>> Programm::run(){
void Programm::fill(unsigned char *data, size_t length, double time){
// für jedes Programm
for(const auto p : Programm::getAllIDBases()){
for(const auto & p : ModelManager::get().getPrograms()){
if(p->isRunning()){
//für jedes Device Programm
for(auto dp_ = p->programms.cbegin();dp_!=p->programms.cend();++dp_){
auto dp = *dp_;
auto & dp = *dp_;
//für jedes Channel Programm
for(const auto cp : dp->getProgrammPrototyp()->getChannelProgramms()){
for(const auto & cp : dp->getProgrammPrototyp()->getChannelProgramms()){
const auto channelNummer = dp->device->getStartDMXChannel() + cp->channel->getIndex();
if(channelNummer<length){
//#warning Fix distorstion:
......@@ -130,26 +132,39 @@ bool Programm::addDeviceProgramm(Device * device, ProgrammPrototype * programmPr
return false;
}
}
auto newDeviceProgramm = new DeviceProgramm(device, programmPrototype, offset);
programms.push_back(newDeviceProgramm);
emit deviceProgrammAdded(newDeviceProgramm);
connect(newDeviceProgramm,&DeviceProgramm::destroyed,this,&Programm::deviceProgrammDeleted);
programms.push_back(std::make_unique<DeviceProgramm>(device, programmPrototype, offset));
emit deviceProgrammAdded(programms.back().get());
// if the device or program prototype gets deleted, we should delete the deviceProgram also
connect(programmPrototype,&ProgrammPrototype::destroyed,this,&Programm::programPrototypeDeleted);
connect(device,&Device::destroyed,this,&Programm::deviceDeleted);
return true;
}
void Programm::removeDeviceProgramm(int index){
if(static_cast<unsigned int>(index)<programms.size())
if(static_cast<unsigned int>(index)<programms.size()){
emit deviceProgrammRemoved(programms[index].get());
programms.erase(programms.cbegin()+index);
}
}
void Programm::deviceProgrammDeleted(QObject *d){
for(auto i = programms.cbegin();i!=programms.cend();++i){
if(*i == d){
programms.erase(i);
emit deviceProgrammRemoved(qobject_cast<DeviceProgramm*>(d));
return;
void Programm::programPrototypeDeleted(QObject * p){
programms.remove_if([this,p](const auto & dp){
if(dp->getProgrammPrototyp() == dynamic_cast<ProgrammPrototype*>(p)){
emit deviceProgrammRemoved(dp.get());
return true;
}
}
return false;
});
}
void Programm::deviceDeleted(QObject * p){
programms.remove_if([this,p](const auto & dp){
if(dp->getDevice() == dynamic_cast<Device*>(p)){
emit deviceProgrammRemoved(dp.get());
return true;
}
return false;
});
}
} // namespace DMX
......@@ -15,7 +15,7 @@ namespace DMX{
*/
class DeviceProgramm : public QObject , public IDBase<DeviceProgramm>{
Q_OBJECT
Q_PROPERTY(ProgrammPrototype* programmPrototype READ getProgrammPrototyp WRITE setProgrammPrototype NOTIFY programmPrototypeChanged)
Q_PROPERTY(ProgrammPrototype* programmPrototype READ getProgrammPrototyp CONSTANT)
Q_PROPERTY(double offset READ getOffset WRITE setOffset NOTIFY offsetChanged)
Q_PROPERTY(double speed READ getSpeed WRITE setSpeed NOTIFY speedChanged)
Q_PROPERTY(Device* device READ getDevice CONSTANT)
......@@ -38,30 +38,16 @@ public:
*/
Q_SLOT void setSpeed(double s){if(s==speed)return;speed=s;emit speedChanged(speed);}
double getSpeed()const{return speed;}
DeviceProgramm(Device * device,ProgrammPrototype * programmPrototype,double offset):QObject(device),programmPrototype(programmPrototype),offset(offset),device(device){
DeviceProgramm(Device * device,ProgrammPrototype * programmPrototype,double offset):programmPrototype(programmPrototype),offset(offset),device(device){
if(!device)
throw new std::runtime_error("Nullpointer Exception: device is nullptr");
if(!programmPrototype)
throw new std::runtime_error("Nullpointer Exception: programmPrototype is nullptr");
connect(programmPrototype,&ProgrammPrototype::destroyed,this,&DeviceProgramm::programmPrototypeDeleted);
}
bool setProgrammPrototype(ProgrammPrototype * p){
if(p->devicePrototype!=device->prototype){
return false;
}
disconnect(programmPrototype,&ProgrammPrototype::destroyed,this,&DeviceProgramm::programmPrototypeDeleted);
programmPrototype = p;