HAL
graph_context.cpp
Go to the documentation of this file.
3 
12 #include "gui/gui_globals.h"
13 #include "gui/gui_def.h"
17 #include <QVector>
18 #include <QJsonArray>
21 
22 namespace hal
23 {
24  static const bool sLazyUpdates = false;
25 
27  : QObject(parent),
28  mId(id_),
29  mName(name),
30  mParentWidget(nullptr),
31  mDirty(false),
32  mLayouter(nullptr),
33  mShader(nullptr),
34  mUserUpdateCount(0),
35  mUnappliedChanges(false),
36  mSceneUpdateRequired(false),
37  mSceneUpdateInProgress(false),
38  mSpecialUpdate(false),
39  mExclusiveModuleId(0)
40  {
41  mTimestamp = QDateTime::currentDateTime();
42  connect(MainWindow::sSettingStyle,&SettingsItemDropdown::intChanged,this,&GraphContext::handleStyleChanged);
43  connect(gNetlistRelay, &NetlistRelay::moduleNameChanged, this, &GraphContext::handleModuleNameChanged);
44  connect(this, &GraphContext::exclusiveModuleLost, this, &GraphContext::handleExclusiveModuleLost);
45  }
46 
48  {
50  if (mParentWidget) mParentWidget->handleContextAboutToBeDeleted();
51  delete mLayouter;
52  delete mShader;
53  }
54 
56  {
57  assert(layouter);
58 
59  if (mLayouter)
60  delete mLayouter;
61 
62  mLayouter = layouter;
63  }
64 
66  {
67  assert(shader);
68 
69  if (mShader)
70  delete mShader;
71 
72  mShader = shader;
73  }
74 
76  {
77  ++mUserUpdateCount;
78  }
79 
81  {
82  --mUserUpdateCount;
83  if (mUserUpdateCount == 0)
84  {
85  evaluateChanges();
86  update();
87  }
88  }
89 
90  void GraphContext::add(const QSet<u32>& modules, const QSet<u32>& gates, PlacementHint placement)
91  {
92  QSet<u32> new_modules = modules - mModules;
93  QSet<u32> new_gates = gates - mGates;
94 
95  QSet<u32> old_modules = mRemovedModules & modules;
96  QSet<u32> old_gates = mRemovedGates & gates;
97 
98  // if we have a placement hint for the added nodes, we ignore it and leave
99  // the nodes where they are (i.e. we just deschedule their removal and not
100  // re-run the placement algo on them)
101  mRemovedModules -= old_modules;
102  mRemovedGates -= old_gates;
103 
104  mAddedModules += new_modules;
105  mAddedGates += new_gates;
106 
107  mPlacementList[placement.mode()].append(
108  PlacementEntry(placement,new_modules,new_gates));
109 
110  if (mUserUpdateCount == 0)
111  {
112  evaluateChanges();
113  update();
114  }
115  if (!new_modules.isEmpty() || !new_gates.isEmpty()) setDirty(true);
116  }
117 
118  void GraphContext::remove(const QSet<u32>& modules, const QSet<u32>& gates)
119  {
120  QSet<u32> old_modules = modules & mModules;
121  QSet<u32> old_gates = gates & mGates;
122 
123  mRemovedModules += old_modules;
124  mRemovedGates += old_gates;
125 
126  mAddedModules -= modules;
127  mAddedGates -= gates;
128 
129  // We don't update mPlacementList here. Keeping elements
130  // in memory is less of an issue than finding the modules/gates _by value_
131  // in the maps and removing them. At the end of applyChanges() the lists are
132  // cleared anyway.
133 
134  if (mUserUpdateCount == 0)
135  {
136  evaluateChanges();
137  update();
138  }
139  if (!old_modules.isEmpty() || !old_gates.isEmpty()) setDirty(true);
140  }
141 
143  {
144  mRemovedModules = mModules;
145  mRemovedGates = mGates;
146 
147  mAddedModules.clear();
148  mAddedGates.clear();
149 
150  for (int i=0; i<4; i++)
151  mPlacementList[i].clear();
152 
153  if (mUserUpdateCount == 0)
154  {
155  evaluateChanges();
156  update();
157  }
158  }
159 
161  {
162  QSet<u32> containedGates = mGates + mAddedGates - mRemovedGates;
163  return containedGates.contains(gateId);
164  }
165 
166  bool GraphContext::isModuleUnfolded(const u32 moduleId) const
167  {
168  QSet<u32> containedGates = mGates + mAddedGates - mRemovedGates;
169  QSet<u32> containedModules = mModules + mAddedModules - mRemovedModules;
170 
171  auto m = gNetlist->get_module_by_id(moduleId);
172 
173  for (const Gate* g : m->get_gates())
174  {
175  if (!containedGates.contains(g->get_id())) return false;
176  }
177  for (const Module* sm : m->get_submodules())
178  {
179  if (!isModuleUnfolded(sm->get_id()) && !containedModules.contains(sm->get_id()))
180  return false;
181  }
182  return true;
183  }
184 
185  void GraphContext::unfoldModule(const u32 id, const PlacementHint& plc)
186  {
187  auto contained_modules = mModules + mAddedModules - mRemovedModules;
188 
189  if (contained_modules.find(id) != contained_modules.end())
190  {
191  auto m = gNetlist->get_module_by_id(id);
194 
195  Node singleContentNode;
196  PlacementHint childPlc;
197 
198  for (const Gate* g : m->get_gates())
199  {
200  singleContentNode = Node(g->get_id(),Node::Gate);
201  gates.insert(g->get_id());
202  }
203  for (const Module* sm : m->get_submodules())
204  {
205  singleContentNode = Node(sm->get_id(),Node::Module);
206  modules.insert(sm->get_id());
207  }
208 
209  if (plc.mode() == PlacementHint::GridPosition)
210  {
211  // placement determined by caller
212  childPlc = plc;
213  }
214  else if (gates.size() + modules.size() == 1)
215  {
216  // There is only a single child in this module, keep the grid position
218  NetLayoutPoint childPos = mLayouter->positonForNode(Node(id,Node::Module));
219  if (!childPos.isUndefined())
220  childPlc.addGridPosition(singleContentNode,childPos);
221  }
222 
223  // That would unfold the empty module into nothing, meaning there would
224  // be no way back
225  assert(!gates.empty() || !modules.empty());
226 
227  beginChange();
228  mLayouter->prepareRollback();
229  remove({id}, {});
230  add(modules, gates, childPlc);
231  endChange();
232  }
233  }
234 
235  bool GraphContext::empty() const
236  {
237  return mGates.empty() && mModules.empty();
238  }
239 
241  {
242  QSet<u32> tempMod = mModules + mAddedModules - mRemovedModules;
243  QSet<u32> tempGat = mGates + mAddedGates - mRemovedGates;
244  return tempMod.isEmpty() && tempGat.isEmpty();
245  }
246 
247  void GraphContext::testIfAffected(const u32 id, const u32* moduleId, const u32* gateId)
248  {
249  if (testIfAffectedInternal(id, moduleId, gateId))
251  }
252 
253  bool GraphContext::testIfAffectedInternal(const u32 id, const u32* moduleId, const u32* gateId)
254  {
255  Node nd(id,Node::Module);
256  if (getLayouter()->boxes().boxForNode(nd))
257  return true;
258 
259  std::vector<Gate*> modifiedGates;
260  if (moduleId)
261  {
262  Module* m = gNetlist->get_module_by_id(*moduleId);
263  if (m) modifiedGates = m->get_gates(nullptr,true);
264  }
265  if (gateId)
266  {
267  Gate* g = gNetlist->get_gate_by_id(*gateId);
268  if (g) modifiedGates.push_back(g);
269  }
270  for (Gate* mg : modifiedGates)
271  if (getLayouter()->boxes().boxForGate(mg))
272  return true;
273 
274  return false;
275  }
276 
277  void GraphContext::removeModuleContents(const u32 moduleId)
278  {
279  QSet<u32> childGates;
280  QSet<u32> childModules;
281 
282  for (const Gate* g : gNetlist->get_module_by_id(moduleId)->get_gates(nullptr, true))
283  {
284  childGates.insert(g->get_id());
285  }
286  for (const Module* sm : gNetlist->get_module_by_id(moduleId)->get_submodules(nullptr, true))
287  {
288  childModules.insert(sm->get_id());
289  }
290  remove(childModules, childGates);
291  }
292 
293  bool GraphContext::isShowingModule(const u32 id) const
294  {
295  return isShowingModule(id, {}, {}, {}, {});
296  }
297 
298  bool GraphContext::isShowingModule(const u32 id, const QSet<u32>& minus_modules, const QSet<u32>& minus_gates, const QSet<u32>& plus_modules, const QSet<u32>& plus_gates) const
299  {
300  // There are all sorts of problems when we allow this, since now any empty
301  // module thinks that it is every other empty module. Blocking this,
302  // however, essentially means that we must destroy all empty contexts:
303  // With the block in place, a context won't recognize it's module anymore
304  // once the last gate has removed, so adding a new gate won't update the
305  // context.
306  if (empty())
307  {
308  return false;
309  }
310 
311  // TODO deduplicate
314 
316 
317  auto contextGates = (mGates - mRemovedGates) + mAddedGates;
318  auto contextModules = (mModules - mRemovedModules) + mAddedModules;
319  auto moduleGates = (gates - minus_gates) + plus_gates;
320  auto moduleModules = (modules - minus_modules) + plus_modules;
321 
322  return contextGates == moduleGates && contextModules == moduleModules;
323  }
324 
325 
327  {
328  auto contextGates = (mGates - mRemovedGates) + mAddedGates;
329  if (!contextGates.isEmpty()) return false;
330  auto contextModules = (mModules - mRemovedModules) + mAddedModules;
331  if (contextModules.size() != 1) return false;
332  return (*mModules.constBegin() == 1); // top_module has ID=1
333  }
334 
335  void GraphContext::getModuleChildrenRecursively(const u32 id, QSet<u32>* gates, QSet<u32>* modules) const
336  {
337 
338  auto containedModules = mModules + mAddedModules - mRemovedModules;
339 
340  Module* m = gNetlist->get_module_by_id(id);
341  if (!m) return;
342 
343  for (const Gate* g : m->get_gates())
344  {
345  gates->insert(g->get_id());
346  }
347  for (const Module* sm : m->get_submodules())
348  {
349  if (!containedModules.contains(sm->get_id()) && isModuleUnfolded(sm->get_id()))
351  else
352  modules->insert(sm->get_id());
353  }
354  }
355 
357  {
358  // Module Context connection is lost when a unfolded submodule (visible in view) is deleted
359  // The connection is lost, because the deletion of an unfolded module does not add its submodules/gates
360  // to the view
361 
362  if (!mExclusiveModuleId) return false;
363 
364  auto containedModules = mModules + mAddedModules - mRemovedModules;
365  auto containedGates = mGates + mAddedGates - mRemovedGates;
366 
367  // folded module
368  if (containedGates.empty() && containedModules.size() == 1 && *containedModules.begin() == mExclusiveModuleId)
369  return true;
370  // unfolded module
371  if (isShowingModule(mExclusiveModuleId, {}, {}, {}, {}))
372  return true;
373  return false;
374  }
375 
376  bool GraphContext::isShowingNetSource(const u32 mNetId) const
377  {
378  auto net = gNetlist->get_net_by_id(mNetId);
379  auto src_pins = net->get_sources();
380 
381  for(auto pin : src_pins)
382  {
383  if(pin->get_gate() != nullptr)
384  {
385  if(mGates.contains(pin->get_gate()->get_id()))
386  return true;
387  }
388  }
389 
390  return false;
391  }
392 
394  {
395  auto net = gNetlist->get_net_by_id(mNetId);
396  auto dst_pins = net->get_destinations();
397 
398  for(auto pin : dst_pins)
399  {
400  if(pin->get_gate() != nullptr)
401  {
402  if(mGates.contains(pin->get_gate()->get_id()))
403  return true;
404  }
405  }
406 
407  return false;
408  }
409 
411  {
412  for (Endpoint* ep : n->get_sources())
413  {
414  Gate* g = ep->get_gate();
415  NodeBox* box = mLayouter->boxes().boxForGate(g);
416  if (box) return box->getNode();
417  }
418  return Node();
419  }
420 
422  {
423  for (Endpoint* ep : n->get_destinations())
424  {
425  Gate* g = ep->get_gate();
426  NodeBox* box = mLayouter->boxes().boxForGate(g);
427  if (box) return box->getNode();
428  }
429  return Node();
430  }
431 
433  {
434  return mModules;
435  }
436 
438  {
439  return mGates;
440  }
441 
443  {
444  return mNets;
445  }
446 
448  {
449  return mLayouter->scene();
450  }
451 
453  {
454  return mId;
455  }
456 
458  {
459  return mName;
460  }
461 
463  {
464  if (mDirty) return mName + "*";
465  return mName;
466  }
467 
469  {
470  return mSceneUpdateInProgress;
471  }
472 
474  {
475  mSceneUpdateRequired = true;
476 
477  if (sLazyUpdates)
478  if (!mParentWidget)
479  return;
480 
481  if(mUserUpdateCount == 0)
482  update();
483  }
484 
485  void GraphContext::refreshModule(const u32 moduleId)
486  {
487  NodeBox* box = getLayouter()->boxes().boxForNode(Node(moduleId,Node::Module));
488  if (!box) return;
489  Module* m = gNetlist->get_module_by_id(moduleId);
490  if (!m) return;
491  GraphicsModule* gm = dynamic_cast<GraphicsModule*>(box->item());
492  if (!gm) return;
493  gm->setModuleLabel(m);
494  gm->update();
495  }
496 
498  {
499  if (mGates.contains(id))
500  return Node(id, Node::Gate);
501 
502  Gate* g = gNetlist->get_gate_by_id(id);
503 
504  if (!g)
505  return Node();
506 
507  Module* m = g->get_module();
508 
509  while (m)
510  {
511  if (mModules.contains(m->get_id()))
512  return Node(m->get_id(), Node::Module);
513  m = m->get_parent_module();
514  }
515 
516  return Node();
517  }
518 
519  /*GraphLayouter* GraphContext::debugGetLayouter() const
520  {
521  return mLayouter;
522  }*/
523 
524  void GraphContext::layoutProgress(int percent) const
525  {
526  QString text;
527  if (!percent) text = QString("Layout %1[%2]").arg(mName).arg(mId);
528  if (mParentWidget) mParentWidget->showProgress(percent,text);
529  }
530 
532  {
533  if (mParentWidget) mParentWidget->storeViewport();
534  }
535 
537  {
538  mLayouter->updatePlacement(plc);
540  }
541 
542  void GraphContext::handleLayouterFinished()
543  {
544  if (mUnappliedChanges)
545  applyChanges();
546 
547  if (mSceneUpdateRequired)
548  {
549  requireSceneUpdate();
550  }
551  else
552  {
553  mShader->update();
554  mLayouter->scene()->updateVisuals(mShader->getShading());
555 
556  mSceneUpdateInProgress = false;
557 
558  mLayouter->scene()->connectAll();
559 
560  if (mParentWidget) mParentWidget->handleSceneAvailable();
561  }
562  }
563 
564  void GraphContext::evaluateChanges()
565  {
566  if (!mAddedGates.isEmpty() || !mRemovedGates.isEmpty() || !mAddedModules.isEmpty() || !mRemovedModules.isEmpty())
567  mUnappliedChanges = true;
568  }
569 
570  void GraphContext::update()
571  {
572  if (mSceneUpdateInProgress)
573  return;
574 
575  storeViewport();
576 
577  if (mUnappliedChanges)
578  applyChanges();
579 
580  if (mSceneUpdateRequired)
581  requireSceneUpdate();
582  }
583 
584  void GraphContext::applyChanges()
585  {
586  // since changes are only applied once in a while added module might not exist any more
587  auto it = mAddedModules.begin();
588  while (it != mAddedModules.end())
589  {
590  if (gNetlist->get_module_by_id(*it))
591  ++it;
592  else
593  it = mAddedModules.erase(it);
594  }
595 
596  mModules -= mRemovedModules;
597  mGates -= mRemovedGates;
598 
599  mModules += mAddedModules;
600  mGates += mAddedGates;
601 
602  mLayouter->remove(mRemovedModules, mRemovedGates, mNets);
603  mShader->remove(mRemovedModules, mRemovedGates, mNets);
604 
605  updateNets();
606 
607  int placementOrder[4] = { PlacementHint::GridPosition,
611 
612  for (int iplc = 0; iplc<4; iplc++)
613  {
614  for (const PlacementEntry& plcEntry : mPlacementList[placementOrder[iplc]])
615  {
616  QSet<u32> modsForHint = plcEntry.mModules;
617  modsForHint &= mAddedModules; // may contain obsolete entries that we must filter out
618  QSet<u32> gatsForHint = plcEntry.mGates;
619  gatsForHint &= mAddedGates;
620  mLayouter->add(modsForHint, gatsForHint, mNets, plcEntry.mPlacementHint);
621  }
622  }
623 
624  mShader->add(mAddedModules, mAddedGates, mNets);
625 
626  mAddedModules.clear();
627  mAddedGates.clear();
628 
629  mRemovedModules.clear();
630  mRemovedGates.clear();
631 
632  for (int i=0; i<4; i++)
633  mPlacementList[i].clear();
634 
635  mUnappliedChanges = false;
636  mSceneUpdateRequired = true;
637  }
638 
640  {
641  mNets.clear();
642  for (const auto& id : mGates)
643  {
644  if (mRemovedGates.contains(id)) continue;
645  auto g = gNetlist->get_gate_by_id(id);
646  if (!g) continue;
647  for (auto net : g->get_fan_in_nets())
648  {
649  //if(!net->is_unrouted() || net->is_global_input_net() || net->is_global_output_net())
650  mNets.insert(net->get_id());
651  }
652  for (auto net : g->get_fan_out_nets())
653  {
654  //if(!net->is_unrouted() || net->is_global_input_net() || net->is_global_output_net())
655  mNets.insert(net->get_id());
656  }
657  }
658  for (const auto& id : mModules)
659  {
660  if (mRemovedModules.contains(id)) continue;
661  auto m = gNetlist->get_module_by_id(id);
662  if (!m) continue;
663  for (auto net : m->get_input_nets())
664  {
665  mNets.insert(net->get_id());
666  }
667  for (auto net : m->get_output_nets())
668  {
669  mNets.insert(net->get_id());
670  }
671  }
672  }
673 
674  void GraphContext::requireSceneUpdate()
675  {
676  if (LayoutLockerManager::instance()->canUpdate(this))
677  startSceneUpdate();
678  }
679 
680  void GraphContext::startSceneUpdate()
681  {
682  mSceneUpdateRequired = false;
683  mSceneUpdateInProgress = true;
684 
685  if (mParentWidget) mParentWidget->handleSceneUnavailable();
686  mLayouter->scene()->disconnectAll();
687 
688  // LayouterTask* task = new LayouterTask(mLayouter);
689  // connect(task, &LayouterTask::finished, this, &GraphContext::handleLayouterFinished, Qt::ConnectionType::QueuedConnection);
690  // gThreadPool->queueTask(task);
691 
693 
694  mLayouter->layout();
695  handleLayouterFinished();
696  }
697 
699  {
700  if (!mSceneUpdateInProgress) return;
701  if (!mLayouter->rollback()) return;
702  mGates.clear();
703  mModules.clear();
704  for (const Node& nd : mLayouter->nodeToPositionMap().keys())
705  {
706  switch (nd.type())
707  {
708  case Node::Module: mModules.insert(nd.id()); break;
709  case Node::Gate: mGates.insert(nd.id()); break;
710  default: break;
711  }
712  }
713  mLayouter->layout();
714  handleLayouterFinished();
715  }
716 
717  void GraphContext::handleStyleChanged(int istyle)
718  {
719  Q_UNUSED(istyle);
720  handleLayouterFinished();
721  }
722 
724  {
727  }
728 
729  void GraphContext::handleModuleNameChanged(Module* m)
730  {
731  if (mExclusiveModuleId == m->get_id())
732  {
733  QString name = QString::fromStdString(m->get_name()) + " (ID: " + QString::number(m->get_id()) + ")";
736  act->exec();
737  }
738  Q_EMIT(dataChanged());
739  }
740 
742  {
743  return mTimestamp;
744  }
745 
747  {
748  if (json.contains("timestamp") && json["timestamp"].isString())
749  mTimestamp = QDateTime::fromString(json["timestamp"].toString());
750 
751  QList<QPair<Node,QPoint>> nodesToPlace;
752 
753  if (json.contains("modules") && json["modules"].isArray())
754  {
755  QJsonArray jsonMods = json["modules"].toArray();
756  int nmods = jsonMods.size();
757  for (int imod=0; imod<nmods; imod++)
758  {
759  QJsonObject jsonMod = jsonMods.at(imod).toObject();
760  if (!jsonMod.contains("id") || !jsonMod["id"].isDouble()) continue;
761  u32 id = jsonMod["id"].toInt();
762  if (!gNetlist->get_module_by_id(id))
763  {
764  log_warning("gui", "Module id={} not found in netlist, view id={} not restored.", id, mId);
765  return false;
766  }
767  if (!jsonMod.contains("x") || !jsonMod["x"].isDouble()) continue;
768  int x = jsonMod["x"].toInt();
769  if (!jsonMod.contains("y") || !jsonMod["y"].isDouble()) continue;
770  int y = jsonMod["y"].toInt();
771  Node nd(id,Node::Module);
772  nodesToPlace.append(QPair<Node,QPoint>(nd,QPoint(x,y)));
773  }
774  }
775 
776  if (json.contains("gates") && json["gates"].isArray())
777  {
778  QJsonArray jsonGats = json["gates"].toArray();
779  int ngats = jsonGats.size();
780  for (int igat=0; igat<ngats; igat++)
781  {
782  QJsonObject jsonGat = jsonGats.at(igat).toObject();
783  if (!jsonGat.contains("id") || !jsonGat["id"].isDouble()) continue;
784  u32 id = jsonGat["id"].toInt();
785  if (!gNetlist->get_gate_by_id(id))
786  {
787  log_warning("gui", "Gate id={} not found in netlist, view id={} not restored.", id, mId);
788  return false;
789  }
790  if (!jsonGat.contains("x") || !jsonGat["x"].isDouble()) continue;
791  int x = jsonGat["x"].toInt();
792  if (!jsonGat.contains("y") || !jsonGat["y"].isDouble()) continue;
793  int y = jsonGat["y"].toInt();
794  Node nd(id,Node::Gate);
795  nodesToPlace.append(QPair<Node,QPoint>(nd,QPoint(x,y)));
796  }
797  }
798 
799  if (nodesToPlace.isEmpty())
800  {
801  log_warning("gui", "Cannot restore view id={}, there are no nodes to place.", mId);
802  return false;
803  }
804 
805  mModules.clear();
806  mGates.clear();
807  for (const QPair<Node,QPoint>& box : nodesToPlace)
808  {
809  if (box.first.type() == Node::Module)
810  mModules.insert(box.first.id());
811  else
812  mGates.insert(box.first.id());
813  mLayouter->setNodePosition(box.first,box.second);
814  }
815  if (mModules.size()==1 && mGates.isEmpty())
816  setExclusiveModuleId(*(mModules.begin()),false);
817 
818  if (json.contains("nets") && json["nets"].isArray())
819  {
820  QJsonArray jsonNets = json["nets"].toArray();
821  int nnets = jsonNets.size();
822  for (int inet=0; inet<nnets; inet++)
823  {
824  QJsonObject jsonNet = jsonNets.at(inet).toObject();
825  if (!jsonNet.contains("id") || !jsonNet["id"].isDouble()) continue;
826  u32 id = jsonNet["id"].toInt();
827  if (!gNetlist->get_net_by_id(id)) return false;
828  mNets.insert(id);
829  }
830  }
831 
832  //scheduleSceneUpdate();
833  setDirty(false);
834  return true;
835  }
836 
837  void GraphContext::writeToFile(QJsonObject& json, int parentId)
838  {
839  json["id"] = (int) mId;
840  json["name"] = mName;
841  json["timestamp"] = mTimestamp.toString();
842  json["exclusiveModuleId"] = (int) mExclusiveModuleId;
843  json["visible"] = gContentManager->getGraphTabWidget()->visibleStatus(this);
844  json["parentId"] = (int) parentId;
846  QJsonArray jsonMods;
847  for (u32 id : mModules)
848  {
850  Q_ASSERT(!pos.isUndefined());
851  QJsonObject jsonMod;
852  jsonMod["id"] = (int) id;
853  jsonMod["x"] = (int) pos.x();
854  jsonMod["y"] = (int) pos.y();
855  jsonMods.append(jsonMod);
856  }
857  json["modules"] = jsonMods;
858 
860  QJsonArray jsonGats;
861  for (u32 id : mGates)
862  {
864  Q_ASSERT(!pos.isUndefined());
865  QJsonObject jsonGat;
866  jsonGat["id"] = (int) id;
867  jsonGat["x"] = (int) pos.x();
868  jsonGat["y"] = (int) pos.y();
869  jsonGats.append(jsonGat);
870  }
871  json["gates"] = jsonGats;
872 
874  QJsonArray jsonNets;
875  for (u32 id : mNets)
876  {
877  QJsonObject jsonNet;
878  jsonNet["id"] = (int) id;
879  jsonNets.append(jsonNet);
880  }
881  json["nets"] = jsonNets;
882  setDirty(false);
883  }
884 
885  void GraphContext::setDirty(bool dty)
886  {
887  if (mDirty==dty) return;
888  mDirty = dty;
889  Q_EMIT(dataChanged());
890  }
891 
892  void GraphContext::setScheduleRemove(const QSet<u32>& mods, const QSet<u32>& gats)
893  {
894  mScheduleRemoveModules = mods;
895  mScheduleRemoveGates = gats;
896  }
897 
899  {
900  switch (nd.type()) {
901  case Node::Module:
902  {
903  auto it = mScheduleRemoveModules.find(nd.id());
904  if (it != mScheduleRemoveModules.end())
905  {
906  mScheduleRemoveModules.erase(it);
907  return true;
908  }
909  break;
910  }
911  case Node::Gate:
912  {
913  auto it = mScheduleRemoveGates.find(nd.id());
914  if (it != mScheduleRemoveGates.end())
915  {
916  mScheduleRemoveGates.erase(it);
917  return true;
918  }
919  break;
920  }
921  default:
922  break;
923  }
924  return false;
925  }
926 
928  {
929  mSpecialUpdate = state;
930  }
931 
933  {
934  if (mParentWidget)
935  mParentWidget->showComments(nd);
936  }
937 
938  void GraphContext::setExclusiveModuleId(u32 id, bool emitSignal)
939  {
940  u32 old_id = mExclusiveModuleId;
941  mExclusiveModuleId = id;
942 
943  // Emit signal if context is not showing an exclusive module anymore
944  if ((id == 0 && old_id != 0) && emitSignal)
945  Q_EMIT(exclusiveModuleLost(old_id));
946  }
947 
948  void GraphContext::handleExclusiveModuleLost(u32 old_id)
949  {
950  Module* m = gNetlist->get_module_by_id(old_id);
951  assert(m);
952 
953  u32 cnt = 0;
954  while (true)
955  {
956  ++cnt;
957  QString new_name = QString::fromStdString(m->get_name()) + " modified";
958  if (cnt > 1)
959  {
960  new_name += " (" + QString::number(cnt) + ")";
961  }
962  bool found = false;
963  for (const auto& ctx : gGraphContextManager->getContexts())
964  {
965  if (ctx->name() == new_name)
966  {
967  found = true;
968  break;
969  }
970  }
971  if (!found)
972  {
973  ActionRenameObject* act = new ActionRenameObject(new_name);
974  act->setObject(UserActionObject(this->id(),UserActionObjectType::ContextView));
975  act->exec();
976  break;
977  }
978  }
979  Q_EMIT(dataChanged());
980  }
981 }
GraphTabWidget * getGraphTabWidget()
Get hal's graph tab widget.
Definition: gate.h:58
bool isModuleUnfolded(const u32 moduleId) const
bool isGateUnfolded(u32 gateId) const
void remove(const QSet< u32 > &modules, const QSet< u32 > &gates)
void setSpecialUpdate(bool state)
void writeToFile(QJsonObject &json, int parentId)
void unfoldModule(const u32 id, const PlacementHint &plc)
void refreshModule(const u32 moduleId)
void showComments(const Node &nd)
GraphicsScene * scene()
bool readFromFile(const QJsonObject &json)
Node getNetSource(const Net *n) const
bool isShowingModuleExclusively()
bool isShowingFoldedTopModule() const
void setDirty(bool dty)
bool isShowingModule(const u32 id) const
void setExclusiveModuleId(u32 id, bool emitSignal=true)
void add(const QSet< u32 > &modules, const QSet< u32 > &gates, PlacementHint placement=PlacementHint())
bool empty() const
void updatePlacement(const GridPlacement &plc)
void layoutProgress(int percent) const
Node getNetDestination(const Net *n) const
const QSet< u32 > & gates() const
const QSet< u32 > & modules() const
void testIfAffected(const u32 id, const u32 *moduleId, const u32 *gateId)
Node nodeForGate(const u32 id) const
void exclusiveModuleLost(u32 old_id)
void setScheduleRemove(const QSet< u32 > &mods, const QSet< u32 > &gats)
void setShader(GraphShader *shader)
bool isScheduledRemove(const Node &nd)
QDateTime getTimestamp() const
GraphLayouter * getLayouter() const
GraphContext(u32 id_, const QString &name, QObject *parent=nullptr)
bool willBeEmptied() const
QString getNameWithDirtyState() const
void setLayouter(GraphLayouter *layouter)
QString name() const
const QSet< u32 > & nets() const
bool isShowingNetSource(const u32 mNetId) const
bool sceneUpdateInProgress() const
bool isShowingNetDestination(const u32 mNetId) const
void getModuleChildrenRecursively(const u32 moduleId, QSet< u32 > *gates, QSet< u32 > *modules) const
QVector< GraphContext * > getContexts() const
Base class for all specific layouters.
virtual void remove(const QSet< u32 > modules, const QSet< u32 > gates, const QSet< u32 > nets)=0
void setNodePosition(const Node &n, const QPoint &p)
virtual void add(const QSet< u32 > modules, const QSet< u32 > gates, const QSet< u32 > nets, PlacementHint placement=PlacementHint())=0
NetLayoutPoint positonForNode(const Node &nd) const
const QMap< Node, QPoint > nodeToPositionMap() const
GraphicsScene * scene() const
const NodeBoxes & boxes() const
void updatePlacement(const GridPlacement &plc)
Base class to store and update visual information about the graph.
Definition: graph_shader.h:47
virtual void add(const QSet< u32 > modules, const QSet< u32 > gates, const QSet< u32 > nets)=0
virtual void update()=0
virtual void remove(const QSet< u32 > modules, const QSet< u32 > gates, const QSet< u32 > nets)=0
const Shading & getShading()
int visibleStatus(const GraphContext *ctx) const
void handleSceneUnavailable()
void showProgress(int percent, const QString &text=QString())
void handleSceneAvailable()
void showComments(const Node &nd)
void handleContextAboutToBeDeleted()
Abstract base class for modules.
void setModuleLabel(const Module *m, bool init=false)
Container for a GraphGraphicsView containing gates, nets, and modules.
void updateVisuals(const GraphShader::Shading &s)
static LayoutLockerManager * instance()
void removeWaitingContext(GraphContext *ctx)
static SettingsItemDropdown * sSettingStyle
Definition: main_window.h:302
Module * get_parent_module() const
Definition: module.cpp:125
const std::vector< Gate * > & get_gates() const
Definition: module.cpp:391
std::string get_name() const
Definition: module.cpp:87
const std::unordered_set< Net * > & get_input_nets() const
Definition: module.cpp:540
std::vector< Module * > get_submodules(const std::function< bool(Module *)> &filter=nullptr, bool recursive=false) const
Definition: module.cpp:259
const std::unordered_set< Net * > & get_output_nets() const
Definition: module.cpp:545
u32 get_id() const
Definition: module.cpp:82
Definition: net.h:58
bool isUndefined() const
Gate * get_gate_by_id(const u32 gate_id) const
Definition: netlist.cpp:193
Module * get_module_by_id(u32 module_id) const
Definition: netlist.cpp:613
Net * get_net_by_id(u32 net_id) const
Definition: netlist.cpp:353
void moduleNameChanged(Module *m) const
The NodeBox class represents a node placed at a grid position within a hal view.
Definition: node_box.h:50
GraphicsNode * item() const
item getter for graphics item object
Definition: node_box.h:124
Node getNode() const
getNode getter for node information
Definition: node_box.h:75
NodeBox * boxForNode(const Node &n) const
boxForNode find NodeBox by node
Definition: node_box.h:200
NodeBox * boxForGate(const Gate *g) const
boxForGate find NodeBox by Gate pointer.
Definition: node_box.h:184
The Node class object represents a module or a gate.
Definition: gui_def.h:61
NodeType type() const
type getter for type information
Definition: gui_def.h:71
@ Module
Definition: gui_def.h:63
@ Gate
Definition: gui_def.h:63
u32 id() const
id getter for ID information
Definition: gui_def.h:77
Container class to store a PlacementHint togerther with a set of modules and gates.
Definition: gui_def.h:298
The PlacementHint class object provides hints for the layouter how new box objects are placed on a vi...
Definition: gui_def.h:211
void addGridPosition(const Node &nd, const QPoint &p)
Definition: gui_def.h:278
PlacementModeType mode() const
mode getter for placement mode type
Definition: gui_def.h:238
void intChanged(int value)
virtual void setObject(const UserActionObject &obj)
Definition: user_action.cpp:32
The UserActionObject class represents a single object used in UserAction.
#define log_warning(channel,...)
Definition: log.h:76
ContentManager * gContentManager
Definition: plugin_gui.cpp:78
GraphContextManager * gGraphContextManager
Definition: plugin_gui.cpp:85
Netlist * gNetlist
Definition: plugin_gui.cpp:80
NetlistRelay * gNetlistRelay
Definition: plugin_gui.cpp:81
n
Definition: test.py:6
quint32 u32
Net * net
std::string name
QDateTime currentDateTime()
QDateTime fromString(const QString &string, Qt::DateFormat format)
QString toString(Qt::DateFormat format) const const
void update(const QRectF &rect)
void append(const QJsonValue &value)
QJsonValue at(int i) const const
int size() const const
bool contains(const QString &key) const const
QJsonObject toObject() const const
void append(const T &value)
bool isEmpty() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int x() const const
int y() const const
QSet::iterator begin()
void clear()
QSet::const_iterator constBegin() const const
bool contains(const T &value) const const
bool empty() const const
QSet::iterator end()
QSet::iterator erase(QSet::iterator pos)
QSet::iterator find(const T &value)
QSet::iterator insert(const T &value)
bool isEmpty() const const
int size() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromStdString(const std::string &str)
QString number(int n, int base)