HAL  v4.5.0-232-g8053ac4b3
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
graph_context_manager.cpp
Go to the documentation of this file.
2 
11 #include "gui/gui_globals.h"
17 #include "hal_core/netlist/gate.h"
20 #include "hal_core/utilities/log.h"
21 
22 #include <QDateTime>
23 #include <QFile>
24 #include <QJsonArray>
25 #include <QJsonDocument>
26 #include <QJsonObject>
27 #include <QTextStream>
28 #include <QDir>
29 
30 namespace hal
31 {
32  SettingsItemCheckbox* GraphContextManager::sSettingNetGroupingToPins = new SettingsItemCheckbox("Net Grouping Color to Gate Pins",
33  "graph_view/net_grp_pin",
34  true,
35  "Appearance:Graph View",
36  "If set net grouping colors are also applied to input and output pins of gates");
37 
38  SettingsItemCheckbox* GraphContextManager::sSettingPanOnMiddleButton = new SettingsItemCheckbox("Pan with Middle Mouse Button",
39  "graph_view/pan_middle_button",
40  false,
41  "Graph View",
42  "If enabled middle mouse button will pan the graphics.\n"
43  "If disabled middle mouse button can be used for rubber band selection.");
44 
45  SettingsItemCheckbox* GraphContextManager::sSettingLayoutOnEveryChange = new SettingsItemCheckbox("Invoke Layout on Every Change",
46  "graph_view/layout_on_chage",
47  false,
48  "Graph View",
49  "If enabled every change will invoke layout() routine,\n"
50  "which will not happen upon rename and recolor otherwise.");
51 
53  : mMaxContextId(0)
54  {
55  mContextTreeModel = new ContextTreeModel(this);
56  mSettingDebugGrid = new SettingsItemCheckbox("GUI Debug Grid",
57  "debug/grid",
58  false,
59  "eXpert Settings:Debug",
60  "Specifies whether the debug grid is displayed in the Graph View. The gird represents the scene as the layouter interprets it.");
61 
62  mSettingDumpJunction = new SettingsItemCheckbox("Dump Junction Data",
63  "debug/junction",
64  false,
65  "eXpert Settings:Debug",
66  "Dump input data from junction router to file 'junction_data.txt' for external debugging.");
67 
68  mSettingParseLayout = new SettingsItemCheckbox("Apply Parsed Position", "graph_view/layout_parse", true, "Graph View", "Use parsed verilog coordinates if available.");
69 
70  mSettingLayoutBoxes = new SettingsItemCheckbox("Optimize Box Layout", "graph_view/layout_boxes", true, "Graph View", "If disabled faster randomized placement.");
71  }
72 
74  {
75  ContextDirectory* contextDir = mContextTreeModel->addDirectory(name, mContextTreeModel->getDirectory(parentId), ++mMaxContextId);
76  return contextDir;
77  }
78 
79 
80  bool GraphContextManager::moveItem(u32 itemId, bool isDirectory, u32 parentId, int row)
81  {
82  ContextTreeItem* itemToMove = nullptr;
83  if (isDirectory)
84  itemToMove = dynamic_cast<ContextTreeItem*>(mContextTreeModel->getDirectory(itemId));
85  else
86  itemToMove = dynamic_cast<ContextTreeItem*>(mContextTreeModel->getContext(itemId));
87 
88  BaseTreeItem* parentItem = parentId
89  ? mContextTreeModel->getDirectory(parentId)
90  : mContextTreeModel->getRootItem();
91  if (!parentItem || !itemToMove) return false;
92 
93  return mContextTreeModel->moveItem(itemToMove, parentItem, row);
94  }
95 
96 
97 
98  u32 GraphContextManager::getParentId(u32 childId, bool isDirectory) const
99  {
100  if (isDirectory)
101  {
102  BaseTreeItem* bti = mContextTreeModel->getDirectory(childId);
103  ContextTreeItem* parentItem = dynamic_cast<ContextTreeItem*>(bti->getParent());
104  if (parentItem) return parentItem->getId();
105  return 0;
106  }
107  GraphContext* context = getContextById(childId);
108  if (!context) return 0;
109  QModelIndex inx = mContextTreeModel->getIndexFromContext(context);
110  if (!inx.isValid()) return 0;
111  BaseTreeItem* bti =mContextTreeModel->getItemFromIndex(inx);
112  if (!bti) return 0;
113  ContextTreeItem* parentItem = dynamic_cast<ContextTreeItem*>(bti->getParent());
114  if (parentItem) return parentItem->getId();
115  return 0;
116  }
117 
119  {
120  GraphContext* context = new GraphContext(++mMaxContextId, name);
121  context->setLayouter(getDefaultLayouter(context));
122  context->setShader(getDefaultShader(context));
123 
124  context->scene()->setDebugGridEnabled(mSettingDebugGrid->value().toBool());
125  connect(mSettingDebugGrid, &SettingsItemCheckbox::boolChanged, context->scene(), &GraphicsScene::setDebugGridEnabled);
126 
127  mContextTreeModel->addContext(context, mContextTreeModel->getDirectory(parentId));
128 
129  Q_EMIT contextCreated(context);
130 
131  return context;
132  }
133 
135  {
136  if (!ctx || ctx->id() == ctxId)
137  return; // nothing to do
138  if (getContextById(ctxId))
139  return; // id is in use
140  ctx->mId = ctxId;
141  if (ctxId > mMaxContextId)
142  mMaxContextId = ctxId;
143  }
144 
145  void GraphContextManager::openModuleInView(u32 moduleId, bool unfold)
146  {
147  const Module* module = gNetlist->get_module_by_id(moduleId);
148 
149  if (!module)
150  return;
151 
152  GraphContext* moduleContext =
154  if (moduleContext)
155  {
156  // open existing view
159  }
160  else
161  {
163  act->setUseCreatedObject();
164  QString name = QString::fromStdString(module->get_name()) + " (ID: " + QString::number(moduleId) + ")";
166  act->addAction(new ActionAddItemsToObject({module->get_id()}, {}));
167  if (unfold) act->addAction(new ActionUnfoldModule(module->get_id()));
168  act->exec();
169  moduleContext = gGraphContextManager->getContextById(act->object().id());
170  moduleContext->setDirty(false);
171  moduleContext->setExclusiveModuleId(module->get_id());
172  }
173  }
174 
176  {
177  QString name = gGraphContextManager->nextViewName("Isolated View");
178 
180  act->setUseCreatedObject();
182  act->addAction(new ActionAddItemsToObject({}, {gateId}));
183  act->exec();
184  }
185 
187  QSet<u32> allGates;
188 
189  Net* net = gNetlist->get_net_by_id(netId);
190 
191  PlacementHint plc(PlacementHint::PlacementModeType::GridPosition);
192  int currentY = -(int)(net->get_num_of_sources()/2);
193  for(auto endpoint : net->get_sources()) {
194  u32 id = endpoint->get_gate()->get_id();
195  allGates.insert(id);
196  plc.addGridPosition(Node(id, Node::NodeType::Gate), {0, currentY++});
197  }
198  currentY = -(int)(net->get_num_of_destinations()/2);
199  for(auto endpoint : net->get_destinations()) {
200  u32 id = endpoint->get_gate()->get_id();
201  allGates.insert(id);
202  plc.addGridPosition(Node(id, Node::NodeType::Gate), {1, currentY++});
203  }
204 
205  QString name = gGraphContextManager->nextViewName("Isolated View");
206 
208  act->setUseCreatedObject();
210  auto actionAITO = new ActionAddItemsToObject({}, allGates);
211  actionAITO->setPlacementHint(plc);
212  act->addAction(actionAITO);
213  act->exec();
214  }
215 
217  {
218  ctx->mName = newName;
219 
220  Q_EMIT contextRenamed(ctx);
221  }
222 
224  {
225  ctxDir->setName(newName);
226 
227  Q_EMIT directoryRenamed(ctxDir);
228  }
229 
231  {
232  Q_EMIT deletingContext(ctx);
233 
234  mContextTreeModel->removeContext(ctx);
235 
236  delete ctx;
237  }
238 
240  {
241  Q_EMIT deletingDirectory(ctxDir);
242 
243  mContextTreeModel->removeDirectory(ctxDir);
244 
245  delete ctxDir;
246  }
247 
249  {
250  return mContextTreeModel->list();
251  }
252 
254  {
255  for (GraphContext* ctx : mContextTreeModel->list())
256  {
257  if (ctx->id() == id)
258  return ctx;
259  }
260  return nullptr;
261  }
262 
264  {
265  BaseTreeItem* bti = mContextTreeModel->getDirectory(id);
266  if (bti)
267  {
268  ContextDirectory* directory = static_cast<ContextTreeItem*>(bti)->directory();
269  if (directory) return directory;
270  }
271 
272  return nullptr;
273  }
274 
276  {
277  for (GraphContext* ctx : mContextTreeModel->list())
278  {
279  if (ctx->name() == name && !ctx->isDirty())
280  return ctx;
281  }
282  return nullptr;
283  }
284 
286  {
287  for (GraphContext* ctx : mContextTreeModel->list())
288  {
289  if (ctx->getExclusiveModuleId() == module_id)
290  return ctx;
291  }
292  return nullptr;
293  }
294 
296  {
297  int cnt = 0;
298 
299  for (;;)
300  {
301  QString name = QString("%1 %2").arg(prefix).arg(++cnt);
302  if (!contextWithNameExists(name)) return name;
303  }
304  }
305 
307  {
308  for (GraphContext* ctx : mContextTreeModel->list())
309  {
310  if (ctx->name() == name)
311  {
312  return true;
313  }
314  }
315  return false;
316  }
317 
319  {
320  for (GraphContext* context : mContextTreeModel->list())
321  if (context->getSpecialUpdate())
322  {
323  context->add({m->get_id()}, {});
324  context->setSpecialUpdate(false);
325  }
326  }
327 
329  {
330  for (GraphContext* context : mContextTreeModel->list())
331  {
332  if (context->getExclusiveModuleId() == m->get_id())
333  {
334  context->setExclusiveModuleId(0, false);
335  deleteGraphContext(context);
336  }
337  else if (context->modules().contains(m->get_id()))
338  {
339  context->remove({m->get_id()}, {});
340 
341  if (context->empty() || context->willBeEmptied())
342  deleteGraphContext(context);
343  }
344  }
345  }
346 
348  {
349  for (GraphContext* context : mContextTreeModel->list())
350  if (context->modules().contains(m->get_id()))
352  context->scheduleSceneUpdate();
353  else
354  context->refreshModule(m->get_id());
355  }
356 
358  {
359  for (GraphContext* context : mContextTreeModel->list())
360  if (context->modules().contains(m->get_id()))
362  context->scheduleSceneUpdate();
363  else
364  context->refreshModule(m->get_id());
365  }
366 
368  {
369  auto gates = m->get_gates();
370  QSet<u32> gateIDs;
371  for (auto g : gates)
372  gateIDs.insert(g->get_id());
373  for (GraphContext* context : mContextTreeModel->list())
374  if (context->modules().contains(m->get_id()) // contains module
375  || context->gates().intersects(gateIDs)) // contains gate from module
377  context->scheduleSceneUpdate();
378  else
379  {
380  context->handleLayouterFinished();
381  context->refreshModule(m->get_id());
382  }
383  // a context can contain a gate from a module if it is showing the module
384  // or if it's showing a parent and the module is unfolded
385  }
386 
387  void GraphContextManager::handleModuleSubmoduleAdded(Module* m, const u32 added_module) const
388  {
389  // dump("ModuleSubmoduleAdded", m->get_id(), added_module);
390 
391  QList<u32> module_ids = {};
392  Module* current_module = m;
393 
394  do
395  {
396  module_ids.append(current_module->get_id());
397  current_module = current_module->get_parent_module();
398  } while (current_module);
399 
400  for (GraphContext* context : mContextTreeModel->list())
401  {
402  if (context->isShowingFoldedTopModule()) continue;
403  // only views bound to a module follow its content, isolated views keep their nodes
404  if (context->getExclusiveModuleId() && context->isShowingModule(m->get_id(), {added_module}, {}, {}, {}) && !context->isShowingModule(added_module, {}, {}, {}, {}))
405  context->add({added_module}, {});
406  else
407  context->testIfAffected(m->get_id(), &added_module, nullptr);
408 
409  // When the module is unfolded and was moved to another folded module visible in view,
410  // remove all gates and submodules of added_module from view
411  if (context->isShowingModule(added_module, {}, {}, {}, {}))
412  {
413  QSet<u32> modules = context->modules();
414  modules.remove(added_module);
415 
416  // modules : all modules visible in graph context view except recently added
417  // module_ids : all anchestors of recently added module
418  // algorithm : remove 'recently added' module from view if it was moved to
419  // (child or grandchild of) another module visible in view
420  for (u32 id : module_ids)
421  if (modules.contains(id))
422  {
423  context->removeModuleContents(added_module);
424  return;
425  }
426  }
427  }
428  }
429 
431  {
432  // FIXME this also triggers on module deletion (not only moving)
433  // and collides with handleModuleRemoved
434  // dump("ModuleSubmoduleRemoved", m->get_id(), removed_module);
435 
436  for (GraphContext* context : mContextTreeModel->list())
437  {
438  if (context->isShowingFoldedTopModule()) continue;
439  // only views bound to a module follow its content, isolated views keep their nodes
440  if (context->isScheduledRemove(Node(removed_module,Node::Module)) ||
441  (context->getExclusiveModuleId() && context->isShowingModule(m->get_id(), {}, {}, {removed_module}, {})))
442  context->remove({removed_module}, {});
443  else
444  context->testIfAffected(m->get_id(), &removed_module, nullptr);
445 
446  if (context->empty() || context->willBeEmptied())
447  deleteGraphContext(context);
448  }
449  }
450 
451  void GraphContextManager::handleModuleGateAssigned(Module* m, const u32 inserted_gate) const
452  {
453  // dump("ModuleGateAssigned", m->get_id(), inserted_gate);
454 
455  QList<u32> module_ids = {};
456  Module* current_module = m;
457 
458  do
459  {
460  module_ids.append(current_module->get_id());
461  current_module = current_module->get_parent_module();
462  } while (current_module);
463 
464  for (GraphContext* context : mContextTreeModel->list())
465  {
466  if (context->isShowingFoldedTopModule()) continue;
467  // only views bound to a module follow its content, isolated views keep their nodes
468  if (context->getExclusiveModuleId() && context->isShowingModule(m->get_id(), {}, {inserted_gate}, {}, {}))
469  context->add({}, {inserted_gate});
470  else
471  context->testIfAffected(m->get_id(), nullptr, &inserted_gate);
472 
473  if (context->gates().contains(inserted_gate))
474  {
475  QSet<u32> modules = context->modules();
476 
477  for (u32 id : module_ids)
478  if (modules.contains(id))
479  {
480  context->remove({}, {inserted_gate});
481  break;
482  }
483  }
484  }
485  }
486 
488  {
489  // dump("ModuleGateRemoved", m->get_id(), removed_gate);
490  for (GraphContext* context : mContextTreeModel->list())
491  {
492  if (context->isShowingFoldedTopModule()) continue;
493  // only views bound to a module follow its content, isolated views keep their nodes
494  if (context->isScheduledRemove(Node(removed_gate,Node::Gate)) ||
495  (context->getExclusiveModuleId() && context->isShowingModule(m->get_id(), {}, {}, {}, {removed_gate})))
496  {
497  context->remove({}, {removed_gate});
498  if (context->empty() || context->willBeEmptied())
499  {
500  deleteGraphContext(context);
501  }
502  // when the module is empty, add the empty folded module to the view
503  else if (m->get_gates().empty() && m->get_submodules().empty())
504  {
505  context->add({m->get_id()}, {});
506  }
507  }
508  // if a module is unfolded, then the gate is not deleted from the view
509  // but the color of the gate changes to its new parent's color
510 
511  else
512  context->testIfAffected(m->get_id(), nullptr, &removed_gate);
513 
517  }
518  }
519 
520  void GraphContextManager::dump(const QString& title, u32 mid, u32 xid) const
521  {
522  QTextStream xout(stdout, QIODevice::WriteOnly);
523  xout << "===" << title << "===" << mid << "===" << xid << "===\n";
524  for (Module* m : gNetlist->get_modules())
525  {
526  xout << "M" << m->get_id() << " SM:";
527  for (Module* sm : m->get_submodules())
528  xout << " " << sm->get_id();
529  xout << " G:";
530  for (Gate* g : m->get_gates())
531  xout << " " << g->get_id();
532  xout << "\n";
533  }
534  xout << "gats:";
535  for (Gate* g : gNetlist->get_gates())
536  xout << " " << g->get_id();
537  xout << "\n";
538 
539  for (GraphContext* ctx : mContextTreeModel->list())
540  {
541  xout << "ctx " << ctx->id() << ":";
542  for (hal::Node nd : ctx->getLayouter()->positionToNodeMap().values())
543  {
544  xout << " " << (nd.type() == Node::Module ? 'm' : 'g') << nd.id();
545  }
546  xout << "\n";
547  }
548  xout << "-------\n";
549  }
550 
552  {
553  Q_UNUSED(pev);
554  Q_UNUSED(pgid);
555  for (GraphContext* context : mContextTreeModel->list())
556  if (context->modules().contains(m->get_id()))
557  {
558  context->updateNets();
559  context->scheduleSceneUpdate();
560  }
561  }
562 
564  {
565  for (GraphContext* context : mContextTreeModel->list())
566  if (context->gates().contains(g->get_id()))
567  context->remove({}, {g->get_id()});
568  }
569 
571  {
572  for (GraphContext* context : mContextTreeModel->list())
573  if (context->gates().contains(g->get_id()))
574  context->scheduleSceneUpdate();
575  }
576 
578  {
579  Q_UNUSED(n)
580 
581  // CAN NETS BE CREATED WITH SRC AND DST INFORMATION ?
582  // IF NOT THIS EVENT DOESNT NEED TO BE HANDLED
583  }
584 
586  {
587  for (GraphContext* context : mContextTreeModel->list())
588  if (context->nets().contains(n->get_id()))
589  context->scheduleSceneUpdate();
590  }
591 
593  {
594  for (GraphContext* context : mContextTreeModel->list())
595  if (context->nets().contains(n->get_id()))
596  context->scheduleSceneUpdate();
597  }
598 
599  void GraphContextManager::handleNetSourceAdded(Net* n, const u32 src_gate_id) const
600  {
601  for (GraphContext* context : mContextTreeModel->list())
602  {
603  if (context->nets().contains(n->get_id()) || context->gates().contains(src_gate_id))
604  {
605  // forcibly apply changes since nets need to be recalculated
606  context->applyChanges();
607  context->scheduleSceneUpdate();
608  }
609  }
610  }
611 
612  void GraphContextManager::handleNetSourceRemoved(Net* n, const u32 src_gate_id) const
613  {
614  UNUSED(src_gate_id);
615 
616  for (GraphContext* context : mContextTreeModel->list())
617  {
618  if (context->nets().contains(n->get_id()))
619  {
620  // forcibly apply changes since nets need to be recalculated
621  context->applyChanges();
622  context->scheduleSceneUpdate();
623  }
624  }
625  }
626 
627  void GraphContextManager::handleNetDestinationAdded(Net* n, const u32 dst_gate_id) const
628  {
629  for (GraphContext* context : mContextTreeModel->list())
630  {
631  if (context->nets().contains(n->get_id()) || context->gates().contains(dst_gate_id))
632  {
633  // forcibly apply changes since nets need to be recalculated
634  context->applyChanges();
635  context->scheduleSceneUpdate();
636  }
637  }
638  }
639 
640  void GraphContextManager::handleNetDestinationRemoved(Net* n, const u32 dst_gate_id) const
641  {
642  UNUSED(dst_gate_id);
643 
644  for (GraphContext* context : mContextTreeModel->list())
645  {
646  if (context->nets().contains(n->get_id()))
647  {
648  // forcibly apply changes since nets need to be recalculated
649  context->applyChanges();
650  context->scheduleSceneUpdate();
651  }
652  }
653  }
654 
656  {
657  for (GraphContext* context : mContextTreeModel->list())
658  {
659  if (context->nets().contains(mNetId) || context->isShowingNetDestination(mNetId))
660  {
661  context->applyChanges();
662  context->scheduleSceneUpdate();
663  }
664  }
665  }
666 
668  {
669  for (GraphContext* context : mContextTreeModel->list())
670  {
671  if (context->nets().contains(mNetId) || context->isShowingNetSource(mNetId))
672  {
673  context->applyChanges();
674  context->scheduleSceneUpdate();
675  }
676  }
677  }
678 
680  {
681  for (GraphContext* context : mContextTreeModel->list())
682  if (context->nets().contains(mNetId))
683  {
684  context->applyChanges();
685  context->scheduleSceneUpdate();
686  }
687  }
688 
690  {
691  for (GraphContext* context : mContextTreeModel->list())
692  if (context->nets().contains(mNetId))
693  {
694  context->applyChanges();
695  context->scheduleSceneUpdate();
696  }
697  }
698 
700  {
701  StandardGraphLayouter* layouter = new StandardGraphLayouter(context);
702  layouter->setDumpJunctionEnabled(mSettingDumpJunction->value().toBool());
703  layouter->setParseLayoutEnabled(mSettingParseLayout->value().toBool());
704  layouter->setLayoutBoxesEnabled(mSettingLayoutBoxes->value().toBool());
705 
709 
710  return layouter;
711  }
712 
714  {
715  return new ModuleShader(context);
716  }
717 
719  {
720  return mContextTreeModel;
721  }
722 
724  {
725  for (GraphContext* context : mContextTreeModel->list())
726  delete context;
727 
728  mContextTreeModel->clear();
729  }
730 
732  {
733  QFile jsFile(filename);
734  if (!jsFile.open(QIODevice::ReadOnly))
735  return nullptr;
736  QJsonDocument jsonDoc = QJsonDocument::fromJson(jsFile.readAll());
737  const QJsonObject& json = jsonDoc.object();
738  GraphContext* firstContext = nullptr;
739  GraphContext* selectedContext = nullptr;
740 
741  if (json.contains("directories") && json["directories"].isArray())
742  {
743  QJsonArray jsonDirectories = json["directories"].toArray();
744  int ndir = jsonDirectories.size();
745  for (int idir = 0; idir < ndir; idir++)
746  {
747  QJsonObject jsondir = jsonDirectories.at(idir).toObject();
748  if (!jsondir.contains("id") || !jsondir["id"].isDouble())
749  continue;
750  u32 dirId = jsondir["id"].toInt();
751  if (!jsondir.contains("name") || !jsondir["name"].isString())
752  continue;
753  QString dirName = jsondir["name"].toString();
754  if (!jsondir.contains("parentId"))
755  continue;
756  u32 dirParentId = jsondir["parentId"].toInt();
757 
758  BaseTreeItem* dirParent = mContextTreeModel->getRootItem();
759 
760  if (dirParentId != 0)
761  dirParent = mContextTreeModel->getDirectory(dirParentId);
762 
763  if (dirId < 0 || dirId > 0x7FFFFFFF)
764  dirId = ++mMaxContextId;
765 
766  mContextTreeModel->addDirectory(dirName, dirParent, dirId);
767  }
768  }
769  if (json.contains("views") && json["views"].isArray())
770  {
771  QJsonArray jsonViews = json["views"].toArray();
772  int nviews = jsonViews.size();
773  for (int iview = 0; iview < nviews; iview++)
774  {
775  QJsonObject jsonView = jsonViews.at(iview).toObject();
776  if (!jsonView.contains("id") || !jsonView["id"].isDouble())
777  continue;
778  u32 viewId = jsonView["id"].toInt();
779  if (!jsonView.contains("name") || !jsonView["name"].isString())
780  continue;
781  QString viewName = jsonView["name"].toString();
782  if (viewId > mMaxContextId)
783  mMaxContextId = viewId;
784  int visibleFlag = 1; // default to visible before flag was invented
785  if (jsonView.contains("visible"))
786  visibleFlag = jsonView["visible"].toInt();
787 
788  u32 viewParentId = 0;
789  if (!jsonView.contains("parentId"))
790  viewParentId = jsonView["parentId"].toInt();
791 
792  BaseTreeItem* viewParent = mContextTreeModel->getRootItem();
793 
794  if (viewParentId != 0) {
795  viewParent = mContextTreeModel->getDirectory(viewParentId);
796  }
797 
798 
800  if (context)
801  {
802  // load view in existing context
803  context->clear();
804  if (viewName != context->mName)
805  renameGraphContextAction(context,viewName);
806  if (!context->readFromFile(jsonView))
807  {
808  log_warning("gui", "failed to set up existing context ID={} from view file {}.", context->id(), filename.toStdString());
809  continue;
810  }
811  }
812  else
813  {
814  // create new context
815  context = new GraphContext(viewId, viewName);
816  context->setLayouter(getDefaultLayouter(context));
817  context->setShader(getDefaultShader(context));
818  // context->setExclusiveModuleId(exclusiveModuleId); TODO exclusive module ID
819  context->scene()->setDebugGridEnabled(mSettingDebugGrid->value().toBool());
820  connect(mSettingDebugGrid, &SettingsItemCheckbox::boolChanged, context->scene(), &GraphicsScene::setDebugGridEnabled);
821 
822  if (!context->readFromFile(jsonView))
823  {
824  log_warning("gui", "failed to create context context ID={} view file {}.", context->id(), filename.toStdString());
825  deleteGraphContext(context);
826  continue;
827  }
828 
829  mContextTreeModel->addContext(context, viewParent);
830  if (visibleFlag)
831  Q_EMIT contextCreated(context);
832  }
833 
834  if (jsonView.contains("exclusiveModuleId"))
835  context->setExclusiveModuleId(jsonView["exclusiveModuleId"].toInt(),false);
836  if (jsonView.contains("selected"))
837  selectedContext = context;
838  if (visibleFlag==2)
839  selectedContext = context;
840  if (!firstContext)
841  firstContext = context;
842  context->setDirty(false);
843  }
844  }
845  if (selectedContext) return selectedContext;
846  return firstContext;
847  }
848 
850  {
851  QFile jsFile(filename);
852  if (!jsFile.open(QIODevice::WriteOnly))
853  return false;
854 
855  QJsonObject json;
856  QJsonArray jsonViews;
857  for (GraphContext* context : mContextTreeModel->list())
858  {
859  BaseTreeItem* parent = mContextTreeModel->getItemFromIndex(mContextTreeModel->getIndexFromContext(context))->getParent();
860  int parentId = 0;
861  if (parent != mContextTreeModel->getRootItem())
862  parentId = static_cast<ContextTreeItem*>(parent)->directory()->id();
863 
864  QJsonObject jsonView;
865  context->writeToFile(jsonView, parentId);
866  jsonViews.append(jsonView);
867  }
868  json["views"] = jsonViews;
869 
870  QJsonArray jsonDirectories;
871  for (ContextDirectory* directory : mContextTreeModel->directoryList())
872  {
873  QJsonObject jsonDirectory;
874  directory->writeToFile(jsonDirectory);
875  jsonDirectories.append(jsonDirectory);
876  }
877  json["directories"] = jsonDirectories;
878  return (jsFile.write(QJsonDocument(json).toJson(QJsonDocument::Compact)) >= 0); // neg return value indicates error
879  }
880 } // namespace hal
Adds an item to a module or grouping.
void setPlacementHint(PlacementHint hint)
(Future) Base class for all tree models related to the details widget.
virtual BaseTreeItem * getParent() const
BaseTreeItem * getRootItem() const
BaseTreeItem * getItemFromIndex(QModelIndex index) const
ContextManagerWidget * getContextManagerWidget()
void setName(QString name_)
void selectViewContext(GraphContext *context)
Base model for the ContextManagerWidget to manage GraphContexts.
bool moveItem(ContextTreeItem *itemToMove, BaseTreeItem *newParent, int row=-1)
void removeDirectory(ContextDirectory *directory)
const QVector< GraphContext * > & list()
QModelIndex getIndexFromContext(GraphContext *context) const
BaseTreeItem * getDirectory(u32 directoryId) const
void removeContext(GraphContext *context)
ContextDirectory * addDirectory(QString name, BaseTreeItem *parentItem, u32 id)
void addContext(GraphContext *context, BaseTreeItem *parent=nullptr)
const QVector< ContextDirectory * > & directoryList()
BaseTreeItem * getContext(u32 contextId) const
Definition: gate.h:59
u32 get_id() const
Definition: gate.cpp:132
Logical container for modules, gates, and nets.
Definition: graph_context.h:55
GraphicsScene * scene()
bool readFromFile(const QJsonObject &json)
void setDirty(bool dty)
void setExclusiveModuleId(u32 id, bool emitSignal=true)
void setShader(GraphShader *shader)
void setLayouter(GraphLayouter *layouter)
void contextRenamed(GraphContext *context)
void handleModuleNameChanged(Module *m) const
static SettingsItemCheckbox * sSettingLayoutOnEveryChange
void renameContextDirectoryAction(ContextDirectory *ctxDir, const QString &newName)
QString nextViewName(const QString &prefix) const
GraphContext * createNewContext(const QString &name, u32 parentId=0)
void handleMarkedGlobalOutput(u32 mNetId)
void renameGraphContextAction(GraphContext *ctx, const QString &newName)
void deleteContextDirectory(ContextDirectory *ctxDir)
void setContextId(GraphContext *ctx, u32 ctxId)
void handleNetNameChanged(Net *n) const
void handleModuleTypeChanged(Module *m) const
GraphContext * getContextById(u32 id) const
bool handleSaveTriggered(const QString &filename)
ContextTreeModel * getContextTreeModel() const
GraphContext * getContextByExclusiveModuleId(u32 module_id) const
void handleMarkedGlobalInput(u32 mNetId)
u32 getParentId(u32 childId, bool isDirectory) const
void handleNetDestinationRemoved(Net *n, const u32 dst_gate_id) const
GraphContext * getCleanContext(const QString &name) const
void handleGateRemoved(Gate *g) const
void handleModuleGateAssigned(Module *m, const u32 inserted_gate) const
bool contextWithNameExists(const QString &name) const
void handleNetSourceRemoved(Net *n, const u32 src_gate_id) const
void handleUnmarkedGlobalOutput(u32 mNetId)
GraphLayouter * getDefaultLayouter(GraphContext *const context) const
void handleUnmarkedGlobalInput(u32 mNetId)
void handleNetDestinationAdded(Net *n, const u32 dst_gate_id) const
void contextCreated(GraphContext *context)
void deleteGraphContext(GraphContext *ctx)
static SettingsItemCheckbox * sSettingPanOnMiddleButton
static SettingsItemCheckbox * sSettingNetGroupingToPins
ContextDirectory * createNewDirectory(const QString &name, u32 parentId=0)
void handleModuleCreated(Module *m) const
void handleModuleSubmoduleAdded(Module *m, const u32 added_module) const
void handleModulePortsChanged(Module *m, PinEvent pev, u32 pgid)
void handleModuleGateRemoved(Module *m, const u32 removed_gate)
bool moveItem(u32 itemId, bool isDirectory, u32 parentId, int row=-1)
void handleModuleColorChanged(Module *m) const
GraphShader * getDefaultShader(GraphContext *const context) const
void directoryRenamed(ContextDirectory *directory)
GraphContext * restoreFromFile(const QString &filename)
void openModuleInView(u32 moduleId, bool unfold)
void handleModuleSubmoduleRemoved(Module *m, const u32 removed_module)
void deletingDirectory(ContextDirectory *directory)
void handleNetSourceAdded(Net *n, const u32 src_gate_id) const
ContextDirectory * getDirectoryById(u32 id) const
void handleGateNameChanged(Gate *g) const
QVector< GraphContext * > getContexts() const
void deletingContext(GraphContext *context)
Base class for all specific layouters.
void setDumpJunctionEnabled(bool enabled)
Base class to store and update visual information about the graph.
Definition: graph_shader.h:47
Module * get_parent_module() const
Definition: module.cpp:126
const std::vector< Gate * > & get_gates() const
Definition: module.cpp:400
std::string get_name() const
Definition: module.cpp:88
std::vector< Module * > get_submodules(const std::function< bool(Module *)> &filter=nullptr, bool recursive=false) const
Definition: module.cpp:268
u32 get_id() const
Definition: module.cpp:83
Specifically stores/updates visual information about a module and its items.
Definition: module_shader.h:37
Definition: net.h:58
u32 get_id() const
Definition: net.cpp:88
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:206
const std::vector< Module * > & get_modules() const
Definition: netlist.cpp:626
Module * get_module_by_id(u32 module_id) const
Definition: netlist.cpp:615
Net * get_net_by_id(u32 net_id) const
Definition: netlist.cpp:355
The Node class object represents a module or a gate.
Definition: gui_def.h:61
@ Module
Definition: gui_def.h:63
@ Gate
Definition: gui_def.h:63
The PlacementHint class object provides hints for the layouter how new box objects are placed on a vi...
Definition: gui_def.h:214
void addGridPosition(const Node &nd, const QPoint &p)
Definition: gui_def.h:281
A SettingsItem representing a Checkbox.
virtual QVariant value() const override
The standard layouter used to layout netlists.
void addAction(UserAction *act)
virtual UserActionObject object() const
Definition: user_action.h:102
uint32_t u32
Definition: defines.h:41
#define UNUSED(expr)
Definition: defines.h:49
#define log_warning(channel,...)
Definition: log.h:76
const Module * module(const Gate *g, const NodeBoxes &boxes)
Definition: defines.h:45
ContentManager * gContentManager
Definition: plugin_gui.cpp:79
PinEvent
Definition: pin_event.h:42
GraphContextManager * gGraphContextManager
Definition: plugin_gui.cpp:86
Netlist * gNetlist
Definition: gui_globals.h:69
Net * net
std::string name
virtual bool open(QIODevice::OpenMode mode) override
QByteArray readAll()
qint64 write(const char *data, qint64 maxSize)
void append(const QJsonValue &value)
QJsonValue at(int i) const const
int size() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonObject object() const const
bool contains(const QString &key) const const
QJsonObject toObject() const const
void append(const T &value)
bool isValid() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
bool contains(const T &value) const const
QSet::iterator insert(const T &value)
bool remove(const T &value)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromStdString(const std::string &str)
QString number(int n, int base)
std::string toStdString() const const
bool toBool() const const