325 lines
13 KiB
C++
325 lines
13 KiB
C++
#include "component_display.h"
|
|
#include "schema_display.h"
|
|
#include "application.h"
|
|
#include "comdel/display/dialog/attribute_dialog.h"
|
|
#include "comdel/display/dialog/single_automatic_dialog.h"
|
|
#include "comdel/display/dialog/memory_dialog.h"
|
|
|
|
#include <QDrag>
|
|
#include <QDragEnterEvent>
|
|
#include <QMimeData>
|
|
|
|
namespace display {
|
|
|
|
Schema::Schema() {
|
|
schema = nullptr;
|
|
library = std::nullopt;
|
|
setRenderHint(QPainter::Antialiasing);
|
|
setAlignment(Qt::AlignCenter);
|
|
this->setScene(&scene);
|
|
this->setAcceptDrops(true);
|
|
}
|
|
|
|
|
|
void Schema::refreshContent() {
|
|
schema = Application::instance()->getSchema();
|
|
library = Application::instance()->getLibrary();
|
|
|
|
components.clear();
|
|
buses.clear();
|
|
scene.clear();
|
|
pins.clear();
|
|
busConnections.clear();
|
|
directConnections.clear();
|
|
|
|
if (schema != nullptr) {
|
|
for (auto &instance: schema->componentInstances) {
|
|
auto group = new display::ComponentGroup(instance);
|
|
for (auto pin: group->getPins()) {
|
|
display::Pin *p = pin;
|
|
domain::ConnectionComponent connection{instance->name, p->getPin().getName()};
|
|
pins.insert(std::make_pair(connection, p));
|
|
}
|
|
components.insert(std::make_pair(instance->name, group));
|
|
scene.addItem(group);
|
|
}
|
|
for (auto &instance: schema->busInstances) {
|
|
if (instance->bus.getDisplayBus().has_value()) {
|
|
auto group = new display::BusGroup(instance);
|
|
buses.insert(std::make_pair(instance->name, group));
|
|
scene.addItem(group);
|
|
}
|
|
}
|
|
for (auto &connection: schema->connections) {
|
|
auto busInstance = dynamic_cast<domain::BusConnectionInstance *>(connection.get());
|
|
if (busInstance != nullptr) {
|
|
auto con = new display::BusConnection(busInstance, components[busInstance->instance->name],
|
|
buses[busInstance->bus->name]);
|
|
busConnections.push_back(con);
|
|
scene.addItem(con);
|
|
}
|
|
auto directInstance = dynamic_cast<domain::DirectConnectionInstance *>(connection.get());
|
|
if (directInstance != nullptr) {
|
|
auto con = new display::DirectConnection(directInstance, components[directInstance->instance->name],
|
|
components[directInstance->secondInstance->name]);
|
|
directConnections.push_back(con);
|
|
scene.addItem(con);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Schema::updateConnections() {
|
|
if (schema != nullptr) {
|
|
for (auto conn: busConnections) {
|
|
conn->updateConnection();
|
|
}
|
|
for (auto conn: directConnections) {
|
|
conn->updateConnection();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Schema::dragEnterEvent(QDragEnterEvent *event) {
|
|
if (event->mimeData()->hasFormat("comdel/component") ||
|
|
event->mimeData()->hasFormat("comdel/bus")) {
|
|
event->acceptProposedAction();
|
|
}
|
|
}
|
|
|
|
void Schema::dropEvent(QDropEvent *event) {
|
|
if (event->mimeData()->hasFormat("comdel/component")) {
|
|
auto component = library->getComponent(event->mimeData()->data("comdel/component").toStdString());
|
|
|
|
auto attributes = populateAttributes(component.getAttributes());
|
|
if(attributes.size() != component.getAttributes().size()) {
|
|
return;
|
|
}
|
|
|
|
auto currentPos = this->mapToScene(event->pos()).toPoint();
|
|
|
|
auto instance = Application::instance()->addComponent(component, attributes, currentPos.x(), currentPos.y());
|
|
|
|
auto group = new display::ComponentGroup(instance);
|
|
scene.addItem(group);
|
|
for (auto pin: group->getPins()) {
|
|
display::Pin *p = pin;
|
|
domain::ConnectionComponent connection{instance->name, p->getPin().getName()};
|
|
pins.insert(std::make_pair(connection, p));
|
|
}
|
|
|
|
components[instance->name] = group;
|
|
|
|
event->acceptProposedAction();
|
|
}
|
|
if (event->mimeData()->hasFormat("comdel/bus")) {
|
|
auto bus = library->getBus(event->mimeData()->data("comdel/bus").toStdString());
|
|
|
|
auto currentPos = this->mapToScene(event->pos()).toPoint();
|
|
|
|
auto instance = Application::instance()->addBus(bus, currentPos.x(), currentPos.y());
|
|
|
|
auto group = new display::BusGroup(instance);
|
|
scene.addItem(group);
|
|
buses[instance->name] = group;
|
|
|
|
event->acceptProposedAction();
|
|
}
|
|
}
|
|
|
|
void Schema::dragMoveEvent(QDragMoveEvent *event) {
|
|
event->acceptProposedAction();
|
|
}
|
|
|
|
void Schema::removeConnectable(QPointF endPoint) {
|
|
auto instance = context.pin->getComponentInstance();
|
|
auto &pin = context.pin->getPin();
|
|
|
|
auto availableConnections = schema->availableConnections(instance->name, pin.getName(), true);
|
|
|
|
for(auto &connection: availableConnections) {
|
|
if(connection.type != domain::ConnectionEntry::BUS) {
|
|
continue;
|
|
}
|
|
auto bus = connection.busInstance.value();
|
|
if(buses[bus->name] == nullptr) {
|
|
continue;
|
|
}
|
|
auto rect = buses[bus->name]->boundingRect();
|
|
rect = QRectF(buses[bus->name]->x(), buses[bus->name]->y(), rect.width(), rect.height());
|
|
|
|
if (rect.contains(endPoint)) {
|
|
auto con = library->getConnection({instance->component.getName(), pin.getName()}, bus->bus.getName());
|
|
if (con.has_value()) {
|
|
auto attributes = populateAttributes(con->getAttributes());
|
|
if(attributes.size() != con->getAttributes().size()) {
|
|
clearSelectable();
|
|
return;
|
|
}
|
|
|
|
auto conInstance = std::make_shared<domain::BusConnectionInstance>(instance, attributes, bus, *con);
|
|
schema->connections.push_back(conInstance);
|
|
|
|
if (conInstance != nullptr) {
|
|
auto c = new display::BusConnection(conInstance.get(), components[conInstance->instance->name],
|
|
buses[conInstance->bus->name]);
|
|
busConnections.push_back(c);
|
|
scene.addItem(c);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto &connection: availableConnections) {
|
|
if(connection.type != domain::ConnectionEntry::COMPONENT) {
|
|
continue;
|
|
}
|
|
auto pinInstance = domain::ConnectionComponent{connection.componentInstance.value()->name, connection.pin.value().getName()};
|
|
auto pin = pins[pinInstance]->getPin().getDisplayPin();
|
|
auto position = pins[pinInstance]->getComponentInstance()->position;
|
|
|
|
auto rect = QRectF(position.first + pin.x, position.second + pin.y, pin.w, pin.h);
|
|
|
|
if (rect.contains(endPoint)) {
|
|
auto name = components[pinInstance.component]->getComponentInstance()->component.getName();
|
|
auto con = library->getConnection({instance->component.getName(), connection.pin.value().getName()},
|
|
{name, pinInstance.pin});
|
|
if (con.has_value()) {
|
|
auto busInstance = Application::instance()->addBus(library->getBus(con->getBus()), 0, 0);
|
|
|
|
std::vector<domain::InstanceAttribute> attributes;
|
|
if(library->getBus(con->getBus()).getType() == domain::Bus::SINGLE_AUTOMATIC) {
|
|
attributes = populateSingleAutomaticConnection(*con);
|
|
} else {
|
|
attributes = populateAttributes(con->getAttributes());
|
|
}
|
|
if(attributes.size() != con->getAttributes().size()) {
|
|
clearSelectable();
|
|
return;
|
|
}
|
|
|
|
auto conInstance = std::make_shared<domain::DirectConnectionInstance>(instance,
|
|
components[pinInstance.component]->getComponentInstance().get(),
|
|
attributes, busInstance.get(),
|
|
*con);
|
|
schema->connections.push_back(conInstance);
|
|
|
|
if (conInstance != nullptr) {
|
|
auto c = new display::DirectConnection(conInstance.get(),
|
|
components[conInstance->instance->name],
|
|
components[conInstance->secondInstance->name]);
|
|
directConnections.push_back(c);
|
|
scene.addItem(c);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
clearSelectable();
|
|
}
|
|
|
|
void Schema::showConnectable(Pin *domainPin) {
|
|
auto &pin = domainPin->getPin();
|
|
|
|
auto availableConnections = schema->availableConnections(domainPin->getComponentInstance()->name, pin.getName(), true);
|
|
|
|
for(auto &connection: availableConnections) {
|
|
if(connection.type != domain::ConnectionEntry::BUS) {
|
|
continue;
|
|
}
|
|
auto bus = connection.busInstance.value();
|
|
auto &group = buses[bus->name];
|
|
if(group == nullptr) {
|
|
continue;
|
|
}
|
|
auto rect = new QGraphicsRectItem(group->boundingRect());
|
|
rect->setBrush(selectedBrush);
|
|
rect->setPos(group->scenePos());
|
|
|
|
auto _rect = rect->rect();
|
|
_rect.setWidth(_rect.width() + 1);
|
|
_rect.setHeight(_rect.height() + 1);
|
|
rect->setRect(_rect);
|
|
|
|
context.selectable.push_back(rect);
|
|
scene.addItem(rect);
|
|
}
|
|
|
|
for (auto &connection: availableConnections) {
|
|
if(connection.type != domain::ConnectionEntry::COMPONENT) {
|
|
continue;
|
|
}
|
|
auto pinInstance = domain::ConnectionComponent{connection.componentInstance.value()->name, connection.pin.value().getName()};
|
|
auto &instance = pins[pinInstance];
|
|
auto rect = new QGraphicsRectItem(instance->boundingRect());
|
|
rect->setBrush(selectedBrush);
|
|
rect->setPen(selectedPen);
|
|
rect->setPos(instance->scenePos());
|
|
|
|
auto _rect = rect->rect();
|
|
_rect.setWidth(_rect.width() + 1);
|
|
_rect.setHeight(_rect.height() + 1);
|
|
rect->setRect(_rect);
|
|
|
|
context.selectable.push_back(rect);
|
|
scene.addItem(rect);
|
|
}
|
|
|
|
}
|
|
|
|
std::vector<domain::InstanceAttribute> Schema::populateAttributes(std::vector<domain::Attribute>& attributes) {
|
|
std::vector<domain::InstanceAttribute> instanceAttributes;
|
|
|
|
for (auto attr: attributes) {
|
|
domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr);
|
|
if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) {
|
|
if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) {
|
|
auto dialog = new MemoryDialog("Postavi memoriju", "Postavi", &attribute, schema->componentInstances);
|
|
if(dialog->exec() == QDialog::Rejected) {
|
|
// if any dialog isn't set, whole creation is rejected
|
|
return {};
|
|
}
|
|
} else {
|
|
auto dialog = new AttributeDialog("Postavi " + attribute.name, "Postavi", &attribute);
|
|
if(dialog->exec() == QDialog::Rejected) {
|
|
// if any dialog isn't set, whole creation is rejected
|
|
return {};
|
|
}
|
|
}
|
|
}
|
|
instanceAttributes.push_back(attribute);
|
|
}
|
|
return instanceAttributes;
|
|
}
|
|
|
|
std::vector<domain::InstanceAttribute> Schema::populateSingleAutomaticConnection(domain::Connection connection) {
|
|
std::vector<domain::InstanceAttribute> instanceAttributes;
|
|
|
|
for (auto attr: connection.getAttributes()) {
|
|
instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr);
|
|
}
|
|
|
|
auto dialog = new display::SingleAutomaticDialog("Postavi sabirnicu", "Postavi", instanceAttributes);
|
|
if(dialog->exec() == QDialog::Rejected) {
|
|
// if dialog is rejected, whole creation is rejected
|
|
return {};
|
|
}
|
|
|
|
return instanceAttributes;
|
|
|
|
}
|
|
|
|
void Schema::clearSelectable() {
|
|
updateConnections();
|
|
|
|
for (auto &item: this->context.selectable) {
|
|
this->scene.removeItem(item);
|
|
delete item;
|
|
}
|
|
this->context.selectable.clear();
|
|
}
|
|
|
|
} // namespace display
|