/*! * paste only one object type so handlePaste can control the order of creation */ static GraphObjectList handlePasteType(GraphDraw *draw, const Poco::JSON::Array::Ptr &graphObjects, const std::string &type) { GraphObjectList newObjects; for (size_t objIndex = 0; objIndex < graphObjects->size(); objIndex++) { const auto jGraphObj = graphObjects->getObject(objIndex); const auto what = jGraphObj->getValue<std::string>("what"); GraphObject *obj = nullptr; if (what != type) continue; if (what == "Block") obj = new GraphBlock(draw); if (what == "Breaker") obj = new GraphBreaker(draw); if (what == "Connection") obj = new GraphConnection(draw); if (what == "Widget") obj = new GraphWidget(draw); if (obj == nullptr) continue; try {obj->deserialize(jGraphObj);} catch (const Pothos::NotFoundException &) { delete obj; continue; } obj->setSelected(true); newObjects.push_back(obj); } return newObjects; }
void GraphEditor::handleBlockXcrement(const int adj) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); GraphObjectList changedObjects; for (auto obj : draw->getObjectsSelected(GRAPH_BLOCK)) { auto block = dynamic_cast<GraphBlock *>(obj); assert(block != nullptr); for (const auto &propKey : block->getProperties()) { auto paramDesc = block->getParamDesc(propKey); if (paramDesc->has("widgetType") and paramDesc->getValue<std::string>("widgetType") == "SpinBox") { const auto newValue = block->getPropertyValue(propKey).toInt() + adj; block->setPropertyValue(propKey, QString("%1").arg(newValue)); changedObjects.push_back(block); break; } } } if (changedObjects.empty()) return; const auto desc = (changedObjects.size() == 1)? changedObjects.front()->getId() : tr("selected"); if (adj > 0) handleStateChange(GraphState("list-add", tr("Increment %1").arg(desc))); if (adj < 0) handleStateChange(GraphState("list-remove", tr("Decrement %1").arg(desc))); }
GraphObjectList GraphDraw::getObjectsSelected(const int selectionFlags) { GraphObjectList objectsSelected; for (auto obj : this->getGraphObjects(selectionFlags)) { if (obj->isSelected()) objectsSelected.push_back(obj); } return objectsSelected; }
GraphObjectList GraphDraw::getObjectsAtPos(const QPoint &pos) { GraphObjectList graphObjs; const auto objs = this->items(pos); for (auto obj : objs) { auto graphObj = dynamic_cast<GraphObject *>(obj); if (graphObj != nullptr) graphObjs.push_back(graphObj); } return graphObjs; }
GraphObjectList GraphEditor::getGraphObjects(const int selectionFlags) const { GraphObjectList all; for (int i = 0; i < this->count(); i++) { for (auto obj : this->getGraphDraw(i)->getGraphObjects(selectionFlags)) { all.push_back(obj); } } return all; }
GraphObjectList GraphDraw::getGraphObjects(const int selectionFlags) { GraphObjectList l; for (auto child : this->items()) { auto o = dynamic_cast<GraphObject *>(child); if (o == nullptr) continue; if (((selectionFlags & GRAPH_BLOCK) != 0) and (qobject_cast<GraphBlock *>(o) != nullptr)) l.push_back(o); if (((selectionFlags & GRAPH_BREAKER) != 0) and (qobject_cast<GraphBreaker *>(o) != nullptr)) l.push_back(o); if (((selectionFlags & GRAPH_CONNECTION) != 0) and (qobject_cast<GraphConnection *>(o) != nullptr)) l.push_back(o); if (((selectionFlags & GRAPH_WIDGET) != 0) and (qobject_cast<GraphWidget *>(o) != nullptr)) l.push_back(o); } return l; }
void GraphEditor::handlePaste(void) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); auto mimeData = QApplication::clipboard()->mimeData(); const bool canPaste = mimeData->hasFormat("text/json/pothos_object_array") and not mimeData->data("text/json/pothos_object_array").isEmpty(); if (not canPaste) return; //extract object array const auto data = mimeData->data("text/json/pothos_object_array"); const std::string dataStr(data.constData(), data.size()); std::istringstream iss(dataStr); Poco::JSON::Parser p; p.parse(iss); auto graphObjects = p.getHandler()->asVar().extract<Poco::JSON::Array::Ptr>(); assert(graphObjects); //rewrite ids std::map<std::string, std::string> oldIdToNew; for (size_t objIndex = 0; objIndex < graphObjects->size(); objIndex++) { const auto jGraphObj = graphObjects->getObject(objIndex); auto oldId = jGraphObj->getValue<std::string>("id"); oldIdToNew[oldId] = this->newId(QString::fromStdString(oldId)).toStdString(); } for (size_t objIndex = 0; objIndex < graphObjects->size();) { for (auto &pair : *graphObjects->getObject(objIndex)) { if (QString::fromStdString(pair.first).endsWith("id", Qt::CaseInsensitive)) { //if not in oldIdToNew, remove from list if (oldIdToNew.count(pair.second) == 0) { graphObjects->remove(objIndex); goto nextObj; } pair.second = oldIdToNew[pair.second]; } } objIndex++; nextObj: continue; } //unselect all objects draw->deselectAllObjs(); //create objects GraphObjectList objsToMove; objsToMove.append(handlePasteType(draw, graphObjects, "Block")); objsToMove.append(handlePasteType(draw, graphObjects, "Breaker")); handlePasteType(draw, graphObjects, "Connection"); //dont append, connection position doesnt matter objsToMove.append(handlePasteType(draw, graphObjects, "Widget")); //deal with initial positions of pasted objects QPointF cornerest(1e6, 1e6); for (auto obj : objsToMove) { cornerest.setX(std::min(cornerest.x(), obj->pos().x())); cornerest.setY(std::min(cornerest.y(), obj->pos().y())); } //determine an acceptable position to center the paste auto view = dynamic_cast<QGraphicsView *>(this->currentWidget()); auto pastePos = view->mapToScene(view->mapFromGlobal(QCursor::pos())); if (not view->sceneRect().contains(pastePos)) { pastePos = view->mapToScene(this->size().width()/2, this->size().height()/2); } //move objects into position for (auto obj : objsToMove) obj->setPos(obj->pos()-cornerest+pastePos); handleStateChange(GraphState("edit-paste", tr("Paste %1").arg(draw->getSelectionDescription()))); }