diff --git a/CMakeLists.txt b/CMakeLists.txt
index ea99bbe..728bae0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 4.0)
project(SHinterface VERSION 1.0 LANGUAGES CXX)
# Set C++ standard
-set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Enable all warnings
diff --git a/remote.html b/remote.html
new file mode 100644
index 0000000..4765978
--- /dev/null
+++ b/remote.html
@@ -0,0 +1,529 @@
+
+
+
+
+
+ SHInterface Control
+
+
+
+
+
+
+
+
+
diff --git a/src/actors/actor.cpp b/src/actors/actor.cpp
index 51c3c84..15a9919 100644
--- a/src/actors/actor.cpp
+++ b/src/actors/actor.cpp
@@ -24,6 +24,7 @@ void Actor::performValueAction(uint8_t value)
ItemUpdateRequest request;
request.type = ITEM_UPDATE_ACTOR;
request.payload = ItemData(QRandomGenerator::global()->generate(), "Item", value);
+ request.changes.value = true;
sigItemUpdate(request);
}
}
@@ -47,9 +48,12 @@ void Actor::makeInactive()
QString Actor::actionName()
{
QString string;
- if(triggerValue == 0 ) string = "off";
- else if(triggerValue == 1 ) string = "on";
- else string = "value to " + QString::number(triggerValue);
+ if(triggerValue == 0 )
+ string = "off";
+ else if(triggerValue == 1 )
+ string = "on";
+ else
+ string = "value to " + QString::number(triggerValue);
return string;
}
diff --git a/src/actors/alarmtime.h b/src/actors/alarmtime.h
index 0d65d84..99c0b7e 100644
--- a/src/actors/alarmtime.h
+++ b/src/actors/alarmtime.h
@@ -39,13 +39,13 @@ public:
virtual void load(const QJsonObject& json, const bool preserve = false);
uint8_t getRepeat();
+ virtual QString getName() const;
public slots:
void run();
virtual void makeActive();
virtual void makeInactive();
- virtual QString getName() const;
void doTick();
void changeTime(const QDateTime& time);
void setRepeat(const uint8_t repeat);
diff --git a/src/actors/timeractor.cpp b/src/actors/timeractor.cpp
index a0a6b1e..d916045 100644
--- a/src/actors/timeractor.cpp
+++ b/src/actors/timeractor.cpp
@@ -7,11 +7,13 @@ TimerActor::TimerActor(const int timeoutSec, QObject *parent): Actor(parent), ti
timer.setSingleShot(true);
}
-void TimerActor::onValueChanged(uint8_t state)
+void TimerActor::onItemUpdated(ItemUpdateRequest update)
{
- if((state && !triggerValue) || (!state && triggerValue))
+ if(update.changes.value && ((update.payload.getValue() && !triggerValue) || (!update.payload.getValue() && triggerValue)))
{
- if(timer.isActive()) timer.stop();
+ qDebug()<<"Timer started";
+ if(timer.isActive())
+ timer.stop();
timer.setInterval(timeoutMsec_);
timer.start();
}
diff --git a/src/actors/timeractor.h b/src/actors/timeractor.h
index 36290d9..f30ff7c 100644
--- a/src/actors/timeractor.h
+++ b/src/actors/timeractor.h
@@ -16,15 +16,15 @@ private slots:
public slots:
- virtual void onValueChanged(uint8_t state);
+ virtual void onItemUpdated(ItemUpdateRequest update) override;
void setTimeout(const int timeoutSec);
public:
explicit TimerActor(const int timeoutSec = 60, QObject *parent = nullptr);
- virtual QString getName() const;
+ virtual QString getName() const override;
int getTimeout();
- virtual void store(QJsonObject& json);
- virtual void load(const QJsonObject& json, bool preserve);
+ virtual void store(QJsonObject& json) override;
+ virtual void load(const QJsonObject& json, bool preserve) override;
};
diff --git a/src/items/fixeditemsource.cpp b/src/items/fixeditemsource.cpp
index b4459ff..b166831 100644
--- a/src/items/fixeditemsource.cpp
+++ b/src/items/fixeditemsource.cpp
@@ -10,5 +10,19 @@ FixedItemSource::FixedItemSource(Microcontroller* micro, QObject *parent):
void FixedItemSource::refresh()
{
- gotItems({powerItem, rgbItem, auxItem}, ITEM_UPDATE_BACKEND);
+ std::vector requests;
+
+ ItemAddRequest request;
+ request.type = ITEM_UPDATE_BACKEND;
+
+ request.payload = powerItem;
+ requests.push_back(request);
+
+ request.payload = rgbItem;
+ requests.push_back(request);
+
+ request.payload = auxItem;
+ requests.push_back(request);
+
+ gotItems(requests);
}
diff --git a/src/items/item.cpp b/src/items/item.cpp
index 7f350a2..6f391c5 100644
--- a/src/items/item.cpp
+++ b/src/items/item.cpp
@@ -13,8 +13,8 @@
#include
-ItemData::ItemData(uint32_t itemIdIn, QString name, uint8_t value, bool loaded, bool hidden, item_value_type_t type):
- name_(name), value_(value), itemId_(itemIdIn), loaded_(loaded), hidden_(hidden), type_(type)
+ItemData::ItemData(uint32_t itemIdIn, QString name, uint8_t value, bool loaded, bool hidden, item_value_type_t type, QString groupName):
+ name_(name), value_(value), itemId_(itemIdIn), loaded_(loaded), hidden_(hidden), type_(type), groupName_(groupName)
{
}
@@ -46,19 +46,49 @@ uint32_t ItemData::id() const
void ItemData::store(QJsonObject &json)
{
- json["Name"] = name_;
+ storeWithChanges(json, ItemFieldChanges(true));
+}
+
+void ItemData::storeWithChanges(QJsonObject& json, const ItemFieldChanges& changes)
+{
json["ItemId"] = static_cast(itemId_);
- json["Value"] = static_cast(value_);
+ json["ValueType"] = type_;
+ if(changes.name)
+ json["Name"] = name_;
+ if(changes.value)
+ json["Value"] = static_cast(value_);
+ if(changes.groupName)
+ json["GroupName"] = groupName_;
}
void ItemData::load(const QJsonObject &json, const bool preserve)
{
+ loadWithChanges(json, preserve);
+}
+
+ItemFieldChanges ItemData::loadWithChanges(const QJsonObject& json, const bool preserve)
+{
+ ItemFieldChanges changes;
if(!preserve)
{
- name_ = json["Name"].toString(name_);
+ if(json.contains("Name"))
+ {
+ name_ = json["Name"].toString();
+ changes.name = true;
+ }
+ if(json.contains("Value"))
+ {
+ value_ = json["Value"].toInt();
+ changes.value = true;
+ }
+ if(json.contains("GroupName"))
+ {
+ groupName_ = json["GroupName"].toString();
+ changes.groupName = true;
+ }
itemId_ = static_cast(json["ItemId"].toDouble(0));
- value_ = json["Value"].toInt();
}
+ return changes;
}
bool ItemData::getLoaded() const
@@ -71,15 +101,23 @@ void ItemData::setLoaded(bool loaded)
loaded_ = loaded;
}
-bool ItemData::hasChanged(const ItemData& other)
+bool ItemData::hasChanged(const ItemData& other) const
{
- if(other != *this)
- return false;
- if(other.getName() != getName())
+ ItemFieldChanges changes(true);
+ return hasChanged(other, changes);
+}
+
+bool ItemData::hasChanged(const ItemData& other, const ItemFieldChanges& changes) const
+{
+ if(changes.name && other.getName() != getName())
return true;
- if(other.getValue() != getValue())
+ if(changes.value && other.getValue() != getValue())
return true;
- if(other.getLoaded() != getLoaded())
+ if(changes.hidden && other.isHidden() != isHidden())
+ return true;
+ if(changes.groupName && other.getGroupName() != getGroupName())
+ return true;
+ if(changes.actors)
return true;
return false;
}
@@ -99,10 +137,20 @@ item_value_type_t ItemData::getValueType()
return type_;
}
+QString ItemData::getGroupName() const
+{
+ return groupName_;
+}
+
+void ItemData::setGroupName(QString groupName)
+{
+ groupName_ = groupName;
+}
+
//item
Item::Item(uint32_t itemIdIn, QString name, uint8_t value, QObject *parent): QObject(parent), ItemData (itemIdIn, name,
- value)
+ value, false, false, ITEM_VALUE_BOOL, "All")
{
}
@@ -131,7 +179,6 @@ void Item::store(QJsonObject &json)
}
}
json["Actors"] = actorsArray;
- json["ValueType"] = type_;
}
void Item::load(const QJsonObject &json, const bool preserve)
@@ -156,13 +203,21 @@ Item& Item::operator=(const ItemData& other)
value_ = other.getValue();
itemId_ = other.id();
hidden_ = other.isHidden();
+ groupName_ = other.getGroupName();
return *this;
}
void Item::requestUpdate(ItemUpdateRequest update)
{
assert(update.type != ITEM_UPDATE_INVALID);
- if(update.type != ITEM_UPDATE_LOADED && value_ == update.payload.getValue())
+ assert(!update.changes.isNone());
+
+ if(update.type == ITEM_UPDATE_LOADED)
+ {
+ qDebug()<<__func__<& actor : update.newActors)
addActor(actor);
@@ -289,14 +348,12 @@ std::shared_ptr- Item::loadItem(const QJsonObject& json)
return newItem;
}
-ItemUpdateRequest Item::createValueUpdateRequest(uint8_t value,
- item_update_type_t type,
+ItemUpdateRequest Item::createValueUpdateRequest(item_update_type_t type,
bool withActors)
{
ItemUpdateRequest update;
update.type = type;
update.payload = *this;
- update.payload.setValueData(value);
if(withActors)
update.newActors = actors_;
return update;
diff --git a/src/items/item.h b/src/items/item.h
index d461006..b12575c 100644
--- a/src/items/item.h
+++ b/src/items/item.h
@@ -11,7 +11,8 @@ class Actor;
typedef enum {
ITEM_VALUE_BOOL = 0,
ITEM_VALUE_UINT,
- ITEM_VALUE_NO_VALUE
+ ITEM_VALUE_NO_VALUE,
+ ITEM_VALUE_ENUM,
} item_value_type_t;
typedef enum {
@@ -23,6 +24,9 @@ typedef enum {
ITEM_UPDATE_INVALID
} item_update_type_t;
+struct ItemFieldChanges;
+struct ItemUpdateRequest;
+
class ItemData
{
protected:
@@ -32,6 +36,8 @@ protected:
bool loaded_;
bool hidden_;
item_value_type_t type_;
+ QString groupName_;
+ std::vector valueNames_;
public:
ItemData(uint32_t itemIdIn = QRandomGenerator::global()->generate(),
@@ -39,7 +45,8 @@ public:
uint8_t value = 0,
bool loaded = false,
bool hidden = false,
- item_value_type_t type = ITEM_VALUE_BOOL);
+ item_value_type_t type = ITEM_VALUE_BOOL,
+ QString groupName = "");
inline bool operator==(const ItemData& in) const
{
@@ -52,7 +59,8 @@ public:
uint32_t id() const;
- bool hasChanged(const ItemData& other);
+ bool hasChanged(const ItemData& other) const;
+ bool hasChanged(const ItemData& other, const ItemFieldChanges& changes) const;
void setName(QString name);
uint8_t getValue() const;
void setValueData(uint8_t value);
@@ -61,19 +69,15 @@ public:
bool isHidden() const;
void setHidden(bool hidden);
item_value_type_t getValueType();
+ QString getGroupName() const;
+ void setGroupName(QString groupName);
+ void storeWithChanges(QJsonObject& json, const ItemFieldChanges& changes);
+ ItemFieldChanges loadWithChanges(const QJsonObject& json, const bool preserve = false);
virtual QString getName() const;
virtual void store(QJsonObject& json);
virtual void load(const QJsonObject& json, const bool preserve = false);
};
-struct ItemUpdateRequest
-{
- item_update_type_t type = ITEM_UPDATE_INVALID;
- ItemData payload;
- std::vector > newActors;
-};
-
-
class Item: public QObject, public ItemData
{
Q_OBJECT
@@ -104,8 +108,7 @@ public:
void setActorsActive(bool in);
void setOverride(const bool in);
bool getOverride();
- ItemUpdateRequest createValueUpdateRequest(uint8_t value,
- item_update_type_t type,
+ ItemUpdateRequest createValueUpdateRequest(item_update_type_t type,
bool withActors = false);
virtual void store(QJsonObject& json);
@@ -118,3 +121,52 @@ protected:
};
+
+struct ItemFieldChanges
+{
+ bool name :1;
+ bool value :1;
+ bool hidden :1;
+ bool type :1;
+ bool groupName :1;
+ bool actors :1;
+ ItemFieldChanges(bool defaultVal = false)
+ {
+ name = defaultVal;
+ value = defaultVal;
+ hidden = defaultVal;
+ type = defaultVal;
+ groupName = defaultVal;
+ actors = false;
+ }
+ inline bool isNone() const
+ {
+ return !name && !value && !hidden && !type && !groupName && !actors;
+ }
+};
+
+struct ItemUpdateRequest
+{
+ item_update_type_t type = ITEM_UPDATE_INVALID;
+ ItemData payload;
+ ItemFieldChanges changes;
+ std::vector > newActors;
+};
+
+struct ItemAddRequest
+{
+ item_update_type_t type = ITEM_UPDATE_INVALID;
+ std::shared_ptr
- payload;
+ ItemFieldChanges changes;
+ inline ItemUpdateRequest updateRequest() const
+ {
+ ItemUpdateRequest update;
+ update.payload = *payload;
+ update.type = type;
+ update.changes = changes;
+ if(changes.actors)
+ update.newActors = payload->getActors();
+ return update;
+ }
+};
+
diff --git a/src/items/itemloadersource.cpp b/src/items/itemloadersource.cpp
index a24e5a5..db5478a 100644
--- a/src/items/itemloadersource.cpp
+++ b/src/items/itemloadersource.cpp
@@ -10,7 +10,7 @@ ItemLoaderSource::ItemLoaderSource(const QJsonObject& json, QObject *parent):
void ItemLoaderSource::refresh()
{
- std::vector> items;
+ std::vector itemAddRequests;
const QJsonArray itemsArray(json["Items"].toArray());
for(int i = 0; i < itemsArray.size(); ++i)
{
@@ -21,11 +21,15 @@ void ItemLoaderSource::refresh()
std::shared_ptr
- newItem = Item::loadItem(itemObject);
if(newItem)
{
- items.push_back(newItem);
qDebug()<<"Loaded item"<getName();
+ ItemAddRequest request;
+ request.type = ITEM_UPDATE_LOADED;
+ request.payload = newItem;
+ request.changes = ItemFieldChanges(true);
+ itemAddRequests.push_back(request);
}
}
- gotItems(items, ITEM_UPDATE_LOADED);
+ gotItems(itemAddRequests);
}
void ItemLoaderSource::updateJson(const QJsonObject& json)
diff --git a/src/items/itemsource.h b/src/items/itemsource.h
index 5c2bba2..1753f75 100644
--- a/src/items/itemsource.h
+++ b/src/items/itemsource.h
@@ -17,7 +17,7 @@ public slots:
virtual void refresh() = 0;
signals:
- void gotItems(std::vector> items, item_update_type_t updateType);
+ void gotItems(std::vector items);
void requestReplaceItems(std::vector> items);
void updateItems(std::vector updates);
};
diff --git a/src/items/itemstore.cpp b/src/items/itemstore.cpp
index 232d319..1b52bf9 100644
--- a/src/items/itemstore.cpp
+++ b/src/items/itemstore.cpp
@@ -6,39 +6,38 @@ ItemStore::ItemStore(QObject *parent): QObject(parent)
{
}
-void ItemStore::addItem(const std::shared_ptr
- & item, item_update_type_t updateType)
+void ItemStore::addItem(const ItemAddRequest& item)
{
+ qDebug()<<"Item add request for"<getName()<id();
std::shared_ptr
- matched = nullptr;
for(unsigned i = 0; i < items_.size(); i++ )
{
- if(*items_[i] == *item)
+ if(*items_[i] == *item.payload)
{
matched = items_[i];
+ assert(matched->id() == items_[i]->id());
break;
}
}
if(!matched)
{
- items_.push_back(std::shared_ptr
- (item));
- connect(item.get(), &Item::updated, this, &ItemStore::itemUpdateSlot);
- qDebug()<<"Item"<getName()<<"added"<<(item->getLoaded() ? "from loaded" : "");
+ items_.push_back(item.payload);
+ connect(item.payload.get(), &Item::updated, this, &ItemStore::itemUpdateSlot);
+ qDebug()<<"Item"<getName()<<"added"<<(item.payload->getLoaded() ? "from loaded" : "");
itemAdded(std::weak_ptr
- (items_.back()));
}
- else
+ else if(!item.changes.isNone())
{
- ItemUpdateRequest request = item->createValueUpdateRequest(item->getValue(),
- updateType,
- updateType == ITEM_UPDATE_LOADED);
- request.newActors = item->getActors();
+ qDebug()<<"Item"<getName()<<"was matched with"<getName()<<"and has changes";
+ ItemUpdateRequest request = item.updateRequest();
updateItem(request);
}
}
-void ItemStore::addItems(const std::vector>& itemIn,
- item_update_type_t updateType)
+void ItemStore::addItems(const std::vector& itemIn)
{
for(unsigned j = 0; j < itemIn.size(); j++)
- addItem(itemIn[j], updateType);
+ addItem(itemIn[j]);
}
void ItemStore::removeItem(const ItemData& item)
@@ -57,8 +56,15 @@ void ItemStore::removeItem(const ItemData& item)
void ItemStore::replaceItems(const std::vector>& items)
{
- qDebug()<<__func__;
- addItems(items, ITEM_UPDATE_LOADED);
+ for(const std::shared_ptr
- & item : items)
+ {
+ ItemAddRequest request;
+ request.changes = ItemFieldChanges(true);
+ request.changes.actors = true;
+ request.type = ITEM_UPDATE_LOADED;
+ request.payload = item;
+ addItem(request);
+ }
std::vector deletedItems;
for(std::shared_ptr
- item : items_)
{
diff --git a/src/items/itemstore.h b/src/items/itemstore.h
index b4bdeaa..93d1b9f 100644
--- a/src/items/itemstore.h
+++ b/src/items/itemstore.h
@@ -39,8 +39,8 @@ signals:
public slots:
void removeItem(const ItemData& item);
- void addItem(const std::shared_ptr
- & item, item_update_type_t updateType);
- void addItems(const std::vector>& itemsIn, item_update_type_t updateType);
+ void addItem(const ItemAddRequest& item);
+ void addItems(const std::vector& itemsIn);
void replaceItems(const std::vector>& items);
void updateItems(const std::vector& updates);
void updateItem(const ItemUpdateRequest& update);
diff --git a/src/main.cpp b/src/main.cpp
index e3a6e03..722f6ed 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -115,12 +115,7 @@ int main(int argc, char *argv[])
QObject::connect(&mainObject.micro, SIGNAL(textRecived(QString)), w, SLOT(changeHeaderLableText(QString)));
QObject::connect(w, &MainWindow::sigSetRgb, &mainObject.micro, &Microcontroller::changeRgbColor);
QObject::connect(w, &MainWindow::sigSave, &mainObject, [&mainObject, settingsPath](){mainObject.storeToDisk(settingsPath);});
- QObject::connect(w,
- &MainWindow::createdItem,
- &globalItems,
- [](std::shared_ptr
- item) {
- globalItems.addItem(item, ITEM_UPDATE_USER);
- });
+ QObject::connect(w, &MainWindow::createdItem, &globalItems, &ItemStore::addItem);
w->show();
}
retVal = a.exec();
@@ -132,9 +127,7 @@ int main(int argc, char *argv[])
{
SecondaryMainObject mainObject(parser.value(hostOption), parser.value(portOption).toInt());
MainWindow w(&mainObject);
- QObject::connect(&w, &MainWindow::createdItem, &globalItems, [](std::shared_ptr
- item) {
- globalItems.addItem(item, ITEM_UPDATE_USER);
- });
+ QObject::connect(&w, &MainWindow::createdItem, &globalItems, &ItemStore::addItem);
QObject::connect(&w, &MainWindow::sigSave, mainObject.tcpClient, &TcpClient::sendItems);
w.show();
diff --git a/src/microcontroller.cpp b/src/microcontroller.cpp
index 0bf8690..8005278 100644
--- a/src/microcontroller.cpp
+++ b/src/microcontroller.cpp
@@ -157,16 +157,31 @@ void Microcontroller::processList(const QString& buffer)
else if(buffer.contains("EOL"))
{
listMode = false;
- gotItems(relayList, ITEM_UPDATE_BACKEND);
+ std::vector requests;
+ for(const std::shared_ptr
- & item : relayList)
+ {
+ ItemAddRequest request;
+ request.changes.name = true;
+ request.changes.value = true;
+ request.payload = item;
+ request.type = ITEM_UPDATE_BACKEND;
+ requests.push_back(request);
+ }
+ gotItems(requests);
relayList.clear();
}
- else listMode = false;
+ else
+ {
+ listMode = false;
+ }
}
void Microcontroller::processRelayState(const QString& buffer)
{
ItemUpdateRequest update;
update.type = ITEM_UPDATE_BACKEND;
+ update.changes.name = true;
+ update.changes.value = true;
update.payload = static_cast(*processRelayLine(buffer));
updateItems({update});
}
diff --git a/src/service/server.cpp b/src/service/server.cpp
index 8d900a2..13fc7f3 100644
--- a/src/service/server.cpp
+++ b/src/service/server.cpp
@@ -25,6 +25,7 @@ void Server::processIncomeingJson(const QByteArray& jsonbytes)
QJsonArray data = json["Data"].toArray();
bool FullList = json["FullList"].toBool(false);
std::vector> items;
+ std::vector fieldChanges;
for(QJsonValueRef itemjson : data)
{
QJsonObject jsonobject = itemjson.toObject();
@@ -33,6 +34,7 @@ void Server::processIncomeingJson(const QByteArray& jsonbytes)
{
qDebug()<<"Server got item"<getName();
item->setLoaded(FullList);
+ fieldChanges.push_back(item->loadWithChanges(jsonobject));
items.push_back(item);
}
}
@@ -43,7 +45,16 @@ void Server::processIncomeingJson(const QByteArray& jsonbytes)
}
else if(!items.empty())
{
- gotItems(items, ITEM_UPDATE_REMOTE);
+ std::vector updates;
+ for(size_t i = 0; i < items.size(); i++)
+ {
+ ItemUpdateRequest request;
+ request.payload = *items[i];
+ request.changes = fieldChanges[i];
+ request.type = ITEM_UPDATE_REMOTE;
+ updates.push_back(request);
+ }
+ updateItems(updates);
}
}
else
diff --git a/src/service/service.cpp b/src/service/service.cpp
index ae75b7e..a43a313 100644
--- a/src/service/service.cpp
+++ b/src/service/service.cpp
@@ -63,7 +63,6 @@ void Service::sendItems()
sendJson(json);
}
-
void Service::processIncomeingJson(const QByteArray& jsonbytes)
{
QJsonDocument doc = QJsonDocument::fromJson(jsonbytes);
@@ -82,7 +81,6 @@ void Service::processIncomeingJson(const QByteArray& jsonbytes)
else if(type == "SensorUpdate")
{
QJsonArray data = json["Data"].toArray();
- qWarning()<<"Got sensor update with no/empty sensors array";
for(QJsonValueRef sensorjson : data)
{
QJsonObject jsonobject = sensorjson.toObject();
diff --git a/src/service/tcpclient.cpp b/src/service/tcpclient.cpp
index 63729d1..afcb473 100644
--- a/src/service/tcpclient.cpp
+++ b/src/service/tcpclient.cpp
@@ -34,20 +34,40 @@ void TcpClient::processIncomeingJson(const QByteArray& jsonbytes)
if(type == "ItemUpdate")
{
QJsonArray data = json["Data"].toArray();
+ bool FullList = json["FullList"].toBool(false);
std::vector> items;
+ std::vector fieldChanges;
for(QJsonValueRef itemjson : data)
{
QJsonObject jsonobject = itemjson.toObject();
std::shared_ptr
- item = Item::loadItem(jsonobject);
if(item)
{
- qDebug()<<"Client got item"<getName();
- item->setLoaded(false);
+ item->setLoaded(FullList);
+ fieldChanges.push_back(item->loadWithChanges(jsonobject));
items.push_back(item);
}
}
- if(!items.empty())
- gotItems(items, ITEM_UPDATE_REMOTE);
+ if(FullList && !items.empty())
+ {
+ qDebug()<<"Client replaceing items";
+ requestReplaceItems(items);
+ }
+ else if(!items.empty())
+ {
+ std::vector itemAddRequests;
+ qDebug()<<"Client updateing items";
+ for(size_t i = 0; i < items.size(); i++)
+ {
+ ItemAddRequest request;
+ request.type = ITEM_UPDATE_REMOTE;
+ request.payload = items[i];
+ request.changes = fieldChanges[i];
+ itemAddRequests.push_back(request);
+ qDebug()<<"Payload"<id();
+ }
+ gotItems(itemAddRequests);
+ }
}
else
{
diff --git a/src/ui/actorsettingsdialog.cpp b/src/ui/actorsettingsdialog.cpp
index f89a1a0..ccd17e5 100644
--- a/src/ui/actorsettingsdialog.cpp
+++ b/src/ui/actorsettingsdialog.cpp
@@ -106,8 +106,11 @@ ActorSettingsDialog::~ActorSettingsDialog()
void ActorSettingsDialog::editAsItem()
{
- ItemSettingsDialog itemSettingsDiag(actor_, this);
+ setModal(false);
+ ItemSettingsDialog itemSettingsDiag(actor_, false, this);
+ itemSettingsDiag.setModal(false);
itemSettingsDiag.exec();
+ setModal(true);
}
void ActorSettingsDialog::setEnabled()
diff --git a/src/ui/itemscrollbox.cpp b/src/ui/itemscrollbox.cpp
index 170a557..55ba900 100644
--- a/src/ui/itemscrollbox.cpp
+++ b/src/ui/itemscrollbox.cpp
@@ -1,15 +1,16 @@
#include "itemscrollbox.h"
#include "ui_relayscrollbox.h"
-#include "../items/auxitem.h"
-#include "../items/messageitem.h"
+#include
+#include
ItemScrollBox::ItemScrollBox(QWidget *parent) :
QWidget(parent),
ui(new Ui::RelayScrollBox)
{
ui->setupUi(this);
- QScroller::grabGesture(ui->scrollArea, QScroller::TouchGesture);
- QScroller::grabGesture(ui->scrollArea, QScroller::LeftMouseButtonGesture);
+
+ ensureTabExists("All");
+ ui->tabWidget->setCurrentIndex(0);
}
ItemScrollBox::~ItemScrollBox()
@@ -23,24 +24,166 @@ void ItemScrollBox::addItem(std::weak_ptr
- item)
{
if(workItem->isHidden())
return;
- widgets_.push_back(new ItemWidget(item));
- ui->relayWidgetVbox->addWidget(widgets_.back());
- connect(widgets_.back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::deleteRequest);
- connect(widgets_.back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::removeItem);
+
+ // Add to "All" tab
+ widgets_["All"].push_back(new ItemWidget(item, false));
+ QWidget* allScrollContent = tabs_["All"].content;
+ QLayout* layout = allScrollContent->layout();
+ layout->removeItem(tabs_["All"].spacer);
+ layout->addWidget(widgets_["All"].back());
+ layout->addItem(tabs_["All"].spacer);
+ connect(widgets_["All"].back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::deleteRequest);
+ connect(widgets_["All"].back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::removeItem);
+
+ addItemToTabs(item);
+ }
+}
+
+void ItemScrollBox::addItemToTabs(std::weak_ptr
- item)
+{
+ if(auto workItem = item.lock())
+ {
+ if(workItem->isHidden())
+ return;
+
+ QString groupName = workItem->getGroupName();
+ if(groupName.isEmpty() || groupName != "All")
+ {
+ ensureTabExists(groupName);
+ ItemWidget* groupWidget = new ItemWidget(item, true);
+ widgets_[groupName].push_back(groupWidget);
+
+ QWidget* scrollContent = tabs_[groupName].content;
+ QLayout* groupLayout = scrollContent->layout();
+ groupLayout->removeItem(tabs_[groupName].spacer);
+ groupLayout->addWidget(groupWidget);
+ groupLayout->addItem(tabs_[groupName].spacer);
+
+ connect(groupWidget, &ItemWidget::deleteRequest, this, &ItemScrollBox::deleteRequest);
+ connect(groupWidget, &ItemWidget::deleteRequest, this, &ItemScrollBox::removeItem);
+
+ connect(widgets_[groupName].back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::deleteRequest);
+ connect(widgets_[groupName].back(), &ItemWidget::deleteRequest, this, &ItemScrollBox::removeItem);
+ }
}
}
void ItemScrollBox::removeItem(const ItemData& item)
{
- for(unsigned i = 0; i < widgets_.size(); i++)
+ QString key = "All";
+ std::vector& widgets = widgets_[key];
+ for(unsigned i = 0; i < widgets.size(); i++)
{
- if(widgets_[i]->controles(item))
+ if(widgets[i]->controles(item))
{
- ui->relayWidgetVbox->removeWidget(widgets_[i]);
- delete widgets_[i];
- widgets_.erase(widgets_.begin()+i);
+ QWidget* tabContent = tabs_[key].content;
+ if(tabContent)
+ {
+ QLayout* layout = tabContent->layout();
+ if(layout)
+ layout->removeWidget(widgets[i]);
+ }
+ delete widgets[i];
+ widgets.erase(widgets.begin()+i);
+ break;
+ }
+ }
+
+ removeItemFromTabs(item);
+ cleanupEmptyTabs();
+}
+
+void ItemScrollBox::removeItemFromTabs(const ItemData& item)
+{
+ for(const QString& key : widgets_.keys())
+ {
+ if(key == "All")
+ continue;
+ std::vector& widgets = widgets_[key];
+ for(unsigned i = 0; i < widgets.size(); i++)
+ {
+ if(widgets[i]->controles(item))
+ {
+ QWidget* tabContent = tabs_[key].content;
+ if(tabContent)
+ {
+ QLayout* layout = tabContent->layout();
+ if(layout)
+ layout->removeWidget(widgets[i]);
+ }
+ delete widgets[i];
+ widgets.erase(widgets.begin()+i);
+ break;
+ }
+ }
+ }
+
+ cleanupEmptyTabs();
+}
+
+
+void ItemScrollBox::onItemUpdate(const ItemUpdateRequest& update)
+{
+ if(!update.changes.groupName)
+ return;
+
+ for(ItemWidget* widget : widgets_["All"])
+ {
+ if(widget->controles(update.payload))
+ {
+ qDebug()<<"ItemUpdate with group change";
+ std::weak_ptr
- item = widget->getItem();
+ removeItemFromTabs(update.payload);
+ addItemToTabs(item);
}
}
}
+void ItemScrollBox::ensureTabExists(const QString& groupName)
+{
+ if(!tabs_.contains(groupName))
+ {
+ Tab tab;
+ tab.scroller = new QScrollArea(ui->tabWidget);
+ tab.scroller->setWidgetResizable(true);
+ tab.scroller->setFrameShape(QFrame::NoFrame);
+ tab.scroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ tab.content = new QWidget(tab.scroller);
+ QVBoxLayout* scrollLayout = new QVBoxLayout(tab.content);
+ scrollLayout->setContentsMargins(0, 0, 0, 0);
+ tab.content->setLayout(scrollLayout);
+ tab.content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ tab.scroller->setWidget(tab.content);
+
+ tab.spacer = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding);
+ scrollLayout->addSpacerItem(tab.spacer);
+
+ ui->tabWidget->addTab(tab.scroller, groupName);
+ tabs_[groupName] = tab;
+ }
+}
+
+void ItemScrollBox::cleanupEmptyTabs()
+{
+ for(auto it = tabs_.begin(); it != tabs_.end(); ++it)
+ {
+ QString groupName = it.key();
+ if(groupName == "All")
+ continue;
+
+ qDebug()<<__func__<layout()->count();
+
+ if(it.value().content->layout()->count() <= 1)
+ {
+ int index = ui->tabWidget->indexOf(tabs_[groupName].scroller);
+ if(index >= 0)
+ ui->tabWidget->removeTab(index);
+ Tab tab = tabs_.take(groupName);
+ delete tab.content;
+ delete tab.scroller;
+ cleanupEmptyTabs();
+ break;
+ }
+ }
+}
diff --git a/src/ui/itemscrollbox.h b/src/ui/itemscrollbox.h
index 54d5fe8..4292aa0 100644
--- a/src/ui/itemscrollbox.h
+++ b/src/ui/itemscrollbox.h
@@ -4,9 +4,9 @@
#include
#include
#include
-#include
+#include
+#include
#include "itemwidget.h"
-#include "../items/relay.h"
#include "../items/item.h"
#include "../items/itemstore.h"
@@ -20,7 +20,16 @@ class ItemScrollBox : public QWidget
{
Q_OBJECT
private:
- std::vector< ItemWidget* > widgets_;
+ struct Tab
+ {
+ QScrollArea* scroller;
+ QWidget* content;
+ QSpacerItem* spacer;
+ };
+
+ QMap tabs_;
+ QMap> widgets_;
+ Ui::RelayScrollBox *ui;
signals:
void deleteRequest(const ItemData& item);
@@ -36,9 +45,15 @@ public slots:
void addItem(std::weak_ptr
- item);
void removeItem(const ItemData& item);
+ void onItemUpdate(const ItemUpdateRequest& update);
private:
- Ui::RelayScrollBox *ui;
+ void ensureTabExists(const QString& groupName);
+ void cleanupEmptyTabs();
+
+private:
+ void addItemToTabs(std::weak_ptr
- item);
+ void removeItemFromTabs(const ItemData& item);
};
#endif // RELAYSCROLLBOX_H
diff --git a/src/ui/itemsettingsdialog.cpp b/src/ui/itemsettingsdialog.cpp
index 08417d3..aa60f01 100644
--- a/src/ui/itemsettingsdialog.cpp
+++ b/src/ui/itemsettingsdialog.cpp
@@ -1,5 +1,6 @@
#include "itemsettingsdialog.h"
#include "ui_itemsettingsdialog.h"
+#include "../items/itemstore.h"
#include "actorsettingsdialog.h"
#include "../actors/alarmtime.h"
#include "../actors/sensoractor.h"
@@ -13,7 +14,7 @@
#include "itemsettingswidgets/relayitemsettingswidget.h"
#include
-ItemSettingsDialog::ItemSettingsDialog(std::shared_ptr
- item, QWidget *parent) :
+ItemSettingsDialog::ItemSettingsDialog(std::shared_ptr
- item, bool noGroup, QWidget *parent) :
QDialog(parent),
item_(item),
ui(new Ui::ItemSettingsDialog)
@@ -22,9 +23,17 @@ ItemSettingsDialog::ItemSettingsDialog(std::shared_ptr
- item, QWidget *pare
setModal(false);
+ if(noGroup)
+ ui->comboBox_Group->setEnabled(false);
+
ui->label_name->setText(item_->getName());
ui->checkBox_Override->setChecked(item_->getOverride());
-
+
+ // Setup group combobox with editable mode for creating new groups
+ ui->comboBox_Group->setEditable(true);
+ ui->comboBox_Group->addItem("All");
+ ui->comboBox_Group->addItems(getExistingGroups());
+ ui->comboBox_Group->setCurrentText(item_->getGroupName());
if(std::shared_ptr relay = std::dynamic_pointer_cast(item_))
{
@@ -48,6 +57,7 @@ ItemSettingsDialog::ItemSettingsDialog(std::shared_ptr
- item, QWidget *pare
connect(ui->pushButton_remove, &QPushButton::clicked, this, &ItemSettingsDialog::removeActor);
connect(ui->pushButton_edit, &QPushButton::clicked, this, &ItemSettingsDialog::editActor);
connect(ui->checkBox_Override, &QPushButton::clicked, this, &ItemSettingsDialog::changeOverride);
+ connect(ui->comboBox_Group, &QComboBox::currentTextChanged, this, &ItemSettingsDialog::changeGroup);
ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("Actor"));
@@ -61,10 +71,23 @@ ItemSettingsDialog::ItemSettingsDialog(std::shared_ptr
- item, QWidget *pare
ItemSettingsDialog::~ItemSettingsDialog()
{
- if(itemSpecificWidget_) delete itemSpecificWidget_;
+ if(itemSpecificWidget_)
+ delete itemSpecificWidget_;
delete ui;
}
+void ItemSettingsDialog::changeGroup()
+{
+ QString newGroup = ui->comboBox_Group->currentText();
+ if(newGroup != item_->getGroupName())
+ {
+ ItemUpdateRequest update = item_->createValueUpdateRequest(ITEM_UPDATE_USER);
+ update.payload.setGroupName(newGroup);
+ update.changes.groupName = true;
+ item_->requestUpdate(update);
+ }
+}
+
void ItemSettingsDialog::changeOverride()
{
item_->setOverride(ui->checkBox_Override->isChecked());
@@ -166,14 +189,21 @@ void ItemSettingsDialog::editActor()
ActorSettingsDialog* dialog;
- if(alarmTime) dialog = new ActorSettingsDialog(alarmTime, this);
- else if(regulator) dialog = new ActorSettingsDialog(regulator, this);
- else if(sensorActor) dialog = new ActorSettingsDialog(sensorActor, this);
- else if(timerActor) dialog = new ActorSettingsDialog(timerActor, this);
- else if(polynomalActor) dialog = new ActorSettingsDialog(polynomalActor, this);
- else if(factorActor) dialog = new ActorSettingsDialog(factorActor, this);
- else dialog = new ActorSettingsDialog(actor, this);
- dialog->setParent(this);
+ if(alarmTime)
+ dialog = new ActorSettingsDialog(alarmTime, this);
+ else if(regulator)
+ dialog = new ActorSettingsDialog(regulator, this);
+ else if(sensorActor)
+ dialog = new ActorSettingsDialog(sensorActor, this);
+ else if(timerActor)
+ dialog = new ActorSettingsDialog(timerActor, this);
+ else if(polynomalActor)
+ dialog = new ActorSettingsDialog(polynomalActor, this);
+ else if(factorActor)
+ dialog = new ActorSettingsDialog(factorActor, this);
+ else
+ dialog = new ActorSettingsDialog(actor, this);
+
dialog->show();
dialog->exec();
@@ -183,5 +213,19 @@ void ItemSettingsDialog::editActor()
ui->tableWidget->item(i, 1)->setText(item_->getActors()[i]->actionName());
ui->tableWidget->item(i, 2)->setText(item_->getActors()[i]->isActive() ? "Y" : "N");
}
+ delete dialog;
}
}
+
+QStringList ItemSettingsDialog::getExistingGroups()
+{
+ QSet uniqueGroups;
+ for(const auto& item : *globalItems.getItems())
+ {
+ if(!item->getGroupName().isEmpty() && item->getGroupName() != "All")
+ {
+ uniqueGroups.insert(item->getGroupName());
+ }
+ }
+ return uniqueGroups.values();
+}
diff --git a/src/ui/itemsettingsdialog.h b/src/ui/itemsettingsdialog.h
index dc2a5af..606261c 100644
--- a/src/ui/itemsettingsdialog.h
+++ b/src/ui/itemsettingsdialog.h
@@ -19,9 +19,10 @@ class ItemSettingsDialog : public QDialog
private:
void loadActorList();
+ QStringList getExistingGroups();
public:
- explicit ItemSettingsDialog(std::shared_ptr
- item, QWidget *parent = nullptr);
+ explicit ItemSettingsDialog(std::shared_ptr
- item, bool noGroup = false, QWidget *parent = nullptr);
~ItemSettingsDialog();
private slots:
@@ -30,6 +31,7 @@ private slots:
void addActor();
void editActor();
void changeOverride();
+ void changeGroup();
private:
Ui::ItemSettingsDialog *ui;
diff --git a/src/ui/itemsettingsdialog.ui b/src/ui/itemsettingsdialog.ui
index 7faeede..c7f4113 100644
--- a/src/ui/itemsettingsdialog.ui
+++ b/src/ui/itemsettingsdialog.ui
@@ -63,6 +63,20 @@
-
+ -
+
+
-
+
+
+ Group:
+
+
+
+ -
+
+
+
+
-
diff --git a/src/ui/itemwidget.cpp b/src/ui/itemwidget.cpp
index c91c5e8..de7544e 100644
--- a/src/ui/itemwidget.cpp
+++ b/src/ui/itemwidget.cpp
@@ -4,10 +4,12 @@
#include
#include
#include
+#include "itemsettingsdialog.h"
-ItemWidget::ItemWidget(std::weak_ptr
- item, QWidget *parent) :
+ItemWidget::ItemWidget(std::weak_ptr
- item, bool noGroupEdit, QWidget *parent) :
QWidget(parent),
item_(item),
+ noGroupEdit_(noGroupEdit),
ui(new Ui::ItemWidget)
{
ui->setupUi(this);
@@ -40,12 +42,13 @@ ItemWidget::ItemWidget(std::weak_ptr
- item, QWidget *parent) :
connect(ui->pushButton, &QPushButton::clicked, this, &ItemWidget::showSettingsDialog);
connect(workingItem.get(), &Item::updated, this, &ItemWidget::onItemUpdated);
connect(ui->pushButton_Remove, &QPushButton::clicked, this, &ItemWidget::deleteItem);
-
}
else
{
disable();
}
+
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
}
void ItemWidget::deleteItem()
@@ -60,7 +63,9 @@ void ItemWidget::moveToValue(int value)
{
if(auto workingItem = item_.lock())
{
- ItemUpdateRequest request = workingItem->createValueUpdateRequest(value, ITEM_UPDATE_USER);
+ ItemUpdateRequest request = workingItem->createValueUpdateRequest(ITEM_UPDATE_USER);
+ request.payload.setValueData(value);
+ request.changes.value = true;
workingItem->requestUpdate(request);
}
else
@@ -71,15 +76,7 @@ void ItemWidget::moveToValue(int value)
void ItemWidget::moveToState(bool state)
{
- if(auto workingItem = item_.lock())
- {
- ItemUpdateRequest request = workingItem->createValueUpdateRequest(state, ITEM_UPDATE_USER);
- workingItem->requestUpdate(request);
- }
- else
- {
- disable();
- }
+ moveToValue(state);
}
void ItemWidget::disable()
@@ -104,8 +101,9 @@ void ItemWidget::showSettingsDialog()
{
if(auto workingItem = item_.lock())
{
- ItemSettingsDialog dialog(workingItem, this);
+ ItemSettingsDialog dialog(workingItem, noGroupEdit_, this);
dialog.exec();
+
}
else disable();
}
diff --git a/src/ui/itemwidget.h b/src/ui/itemwidget.h
index 90d5a97..51c642f 100644
--- a/src/ui/itemwidget.h
+++ b/src/ui/itemwidget.h
@@ -3,7 +3,6 @@
#include
#include
-#include "itemsettingsdialog.h"
#include "../items/item.h"
namespace Ui
@@ -16,6 +15,7 @@ class ItemWidget : public QWidget
Q_OBJECT
private:
std::weak_ptr
- item_;
+ bool noGroupEdit_;
void disable();
@@ -30,7 +30,7 @@ private slots:
void deleteItem();
public:
- explicit ItemWidget(std::weak_ptr
- item, QWidget *parent = nullptr);
+ explicit ItemWidget(std::weak_ptr
- item, bool noGroupEdit = false, QWidget *parent = nullptr);
std::weak_ptr
- getItem();
bool controles(const ItemData& relay);
~ItemWidget();
diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp
index 79a6b3e..369d3e9 100644
--- a/src/ui/mainwindow.cpp
+++ b/src/ui/mainwindow.cpp
@@ -24,6 +24,7 @@ MainWindow::MainWindow(MainObject * const mainObject, QWidget *parent) :
connect(ui->pushButton_refesh, &QPushButton::clicked, mainObject, &MainObject::refresh);
connect(&globalItems, &ItemStore::itemAdded, ui->relayList, &ItemScrollBox::addItem);
connect(&globalItems, &ItemStore::itemDeleted, ui->relayList, &ItemScrollBox::removeItem);
+ connect(&globalItems, &ItemStore::itemUpdated, ui->relayList, &ItemScrollBox::onItemUpdate);
for(size_t i = 0; i < globalItems.getItems()->size(); ++i)
ui->relayList->addItem(globalItems.getItems()->at(i));
@@ -65,7 +66,7 @@ void MainWindow::showPowerItemDialog()
}
if(powerItem)
{
- ItemSettingsDialog diag(std::shared_ptr
- (powerItem), this);
+ ItemSettingsDialog diag(std::shared_ptr
- (powerItem), false, this);
diag.show();
diag.exec();
}
@@ -79,7 +80,13 @@ void MainWindow::showItemCreationDialog()
ItemCreationDialog diag(this);
diag.show();
if(diag.exec())
- createdItem(diag.item);
+ {
+ ItemAddRequest request;
+ request.type = ITEM_UPDATE_USER;
+ request.changes = ItemFieldChanges(true);
+ request.payload = diag.item;
+ createdItem(request);
+ }
}
void MainWindow::changeHeaderLableText(QString string)
diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h
index 5b04b64..efd9709 100644
--- a/src/ui/mainwindow.h
+++ b/src/ui/mainwindow.h
@@ -32,7 +32,7 @@ private:
signals:
void sigSave();
- void createdItem(std::shared_ptr
- item);
+ void createdItem(ItemAddRequest request);
void sigSetRgb(const QColor color);
private slots:
diff --git a/src/ui/mainwindow.ui b/src/ui/mainwindow.ui
index baa31c8..422862d 100644
--- a/src/ui/mainwindow.ui
+++ b/src/ui/mainwindow.ui
@@ -94,7 +94,7 @@
- 400
+ 350
0
diff --git a/src/ui/relayscrollbox.ui b/src/ui/relayscrollbox.ui
index cb0fae2..7ef7dc2 100644
--- a/src/ui/relayscrollbox.ui
+++ b/src/ui/relayscrollbox.ui
@@ -13,52 +13,15 @@
Form
-
+
-
-
-
- QFrame::NoFrame
+
+
+ false
-
- 0
-
-
- Qt::ScrollBarAlwaysOff
-
-
- Qt::ScrollBarAlwaysOff
-
-
+
true
-
-
-
- 0
- 0
- 388
- 288
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-