HAL
module_pins_tree_model.cpp
Go to the documentation of this file.
2 
4 #include "gui/gui_globals.h"
10 #include "hal_core/netlist/net.h"
12 
13 #include <QDebug>
14 #include <QMimeData>
15 
16 namespace hal
17 {
18  ModulePinsTreeItem::ModulePinsTreeItem(Type itype, u32 id_, QString pinName, PinDirection dir, PinType ptype, int inx, QString netName)
19  : mItemType(itype), mId(id_), mPinName(pinName), mPinDirection(dir), mPinType(ptype), mNetName(netName), mIndex(inx)
20  {;}
21 
23  {
24  switch (index)
25  {
26  case 0:
27  return mPinName;
28  case 1:
29  if (mItemType==ModulePinsTreeItem::Group)
30  return (QString("[%1] %2").arg(getChildCount()).arg(mIndex ? QChar(0x2193) : QChar(0x2191)));
31  return mIndex;
32  case 2:
33  return QString::fromStdString(enum_to_string(mPinDirection));
34  case 3:
35  return QString::fromStdString(enum_to_string(mPinType));
36  case 4:
37  return mNetName;
38  }
39  return QVariant();
40  }
41 
43  {
44  Q_ASSERT(data.size() >= 5);
45  mPinName = data[0].toString();
46  mIndex = data[1].toInt();
47  mPinDirection = enum_from_string<PinDirection>(data[2].toString().toStdString());
48  mPinType = enum_from_string<PinType>(data[3].toString().toStdString());
49  mNetName = data[4].toString();
50  }
51 
53  {
54  switch (column)
55  {
56  case 0:
57  mPinName = data.toString();
58  break;
59  case 1:
60  mIndex = data.toInt();
61  break;
62  case 2:
63  mPinDirection = enum_from_string<PinDirection>(data.toString().toStdString());
64  break;
65  case 3:
66  mPinType = enum_from_string<PinType>(data.toString().toStdString());
67  break;
68  case 4:
69  mNetName = data.toString();
70  break;
71  }
72  }
73 
75  {
76  Q_UNUSED(data)
77  }
78 
80  {
81  return 5;
82  }
83 
85  {
86  setHeaderLabels(QStringList() << "Name "
87  << "Size/Index"
88  << "Direction"
89  << "Type"
90  << "Connected Net");
92 
93  //connections
95  }
96 
98  {
99  delete mRootItem;
100  }
101 
103  {
104 // Qt::ItemFlags defaultFlags = BaseTreeModel::flags(index);
105 // TreeItem* item = index.isValid() ? getItemFromIndex(index) : nullptr;
106 // if (item)
107 // {
108 // //get parent, must be a pingroup item and not the root (not allowed to drag from external group, but maybe later)
109 // TreeItem* parentItem = item->getParent();
110 // itemType type = getTypeOfItem(item);
111 // if (type == itemType::portMultiBit)
112 // return defaultFlags | Qt::ItemIsDropEnabled;
113 // else if (type == itemType::pin) // && parentItem != mRootItem)//only case that should be possible
114 // return defaultFlags | Qt::ItemIsDragEnabled; // | Qt::ItemIsDropEnabled;
115 // if (parentItem == mRootItem && type == itemType::pin)
116 // return defaultFlags;
117 // }
118  // valid-check must be ommitted when a drop between pingroups is desired, all checks are performed in canDropMimeData
120 // if(item)
121 // {
122 // // everything can be dragged, but wether it can be dropped on or not depends on the situation
123 // // -> a pin cannot be dropped onto its parent-group (but it can be dropped within its group),
124 // // and a pingroup cannot be dropped onto (or between) a pin. -> what is currently dragged can only
125 // // be checked in the "canDropMimeData" function, ItemIsDropEnabled cannot be set since its conditional on the dragged item
126 // return defaultFlags | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
127 
128 // }
129 // return defaultFlags;
130  }
131 
132  QModelIndex ModulePinsTreeModel::getIndexFromPinsItem(ModulePinsTreeItem *item) const
133  {
134  if (mOrphanedItem.contains(item)) return QModelIndex();
135  return getIndexFromItem(item);
136  }
137 
138 
140  {
141  QStringList types;
142  types << "pintreemodel/item";
143  return types;
144  }
145 
146  QMimeData* ModulePinsTreeModel::mimeData(const QModelIndexList& indexes) const
147  {
148  if (indexes.size() != 5) //columncount, only 1 item is allowed
149  return new QMimeData();
150 
151  QMimeData* data = new QMimeData();
152  ModulePinsTreeItem* item = static_cast<ModulePinsTreeItem*>(getItemFromIndex(indexes.at(0)));
153  QByteArray encodedData;
154  QDataStream stream(&encodedData, QIODevice::WriteOnly);
155  QString type = item->itemType() == ModulePinsTreeItem::Pin ? "pin" : "group";
156  stream << type << item->id();
157  data->setText(item->itemType() == ModulePinsTreeItem::Pin
158  ? PyCodeProvider::pyCodeModulePinById(mModule->get_id(),item->id())
159  : PyCodeProvider::pyCodeModulePinGroup(mModule->get_id(),item->id()));
160  data->setData("pintreemodel/item", encodedData);
161  return data;
162  }
163 
164  bool ModulePinsTreeModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
165  {
166  Q_UNUSED(action)
167  Q_UNUSED(column)
168 
169  QString type;
170  int id;
171  QByteArray encItem = data->data("pintreemodel/item");
172  QDataStream dataStream(&encItem, QIODevice::ReadOnly);
173 // debug pingroup qDebug() << "dropMimeData" << encItem << row << column;
174  dataStream >> type >> id;
175 
176  auto droppedItem = (type == "group") ? static_cast<ModulePinsTreeItem*>(mIdToGroupItem.value(id)) : static_cast<ModulePinsTreeItem*>(mIdToPinItem.value(id));
177  //auto droppedParentItem = droppedItem->getParent();
178  auto dropPositionItem = getItemFromIndex(parent);
179 
180  // perhaps helper functions?
181  // 1. group on group (between group)
182  // 2. pin on group
183  // 3. pin between groups
184  // 4. pin between pins
185 
186  // put ignore flags here? perhaps needed specifically in other places in functions..
187  if(type == "group")
188  {
189  if(!dropPositionItem)
190  {
191 // debug pingroup qDebug() << "group was dropped between groups... with row: " << row; //check in canDropMine if its not an adjacent row?
192  dndGroupBetweenGroup(droppedItem, row);
193  }
194  else
195  {
196  ModulePinsTreeItem* pitem = dynamic_cast<ModulePinsTreeItem*>(dropPositionItem);
197  if (pitem && pitem->itemType() == ModulePinsTreeItem::Pin)
198  {
199  // debug pingroup qDebug() << "group was dropped on a pin...";
200  ModulePinsTreeItem* parentGroupItem = static_cast<ModulePinsTreeItem*>(pitem->getParent());
201  row = getIndexFromPinsItem(pitem).row();
202  dndGroupOnGroup(droppedItem, parentGroupItem, row);
203  }
204  else
205  // debug pingroup qDebug() << "group was dropped on a group?";
206  dndGroupOnGroup(droppedItem, dropPositionItem);
207  }
208  }
209  else
210  {
211  if(!dropPositionItem)
212  {
213 // debug pingroup qDebug() << "pin was dropped between groups on row " << row;
214  dndPinBetweenGroup(droppedItem, row);
215  }
216  else if(row != -1)
217  {
218 // debug pingroup qDebug() << "pin was dropped between pins";
219  dndPinBetweenPin(droppedItem, dropPositionItem, row);
220  }
221  else
222  {
223  ModulePinsTreeItem* pitem = dynamic_cast<ModulePinsTreeItem*>(dropPositionItem);
224  if (pitem && pitem->itemType() == ModulePinsTreeItem::Pin)
225  {
226 // debug pingroup qDebug() << "pin was dropped on a pin...";
227  ModulePinsTreeItem* parentGroupItem = static_cast<ModulePinsTreeItem*>(pitem->getParent());
228  row = getIndexFromPinsItem(pitem).row();
229  dndPinBetweenPin(droppedItem, parentGroupItem, row);
230  }
231  else
232 // debug pingroup qDebug() << "pin was dropped on a group...";
233  dndPinOnGroup(droppedItem, dropPositionItem);
234  }
235  }
236 
237  return true;
238  }
239 
240 
241  bool ModulePinsTreeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
242  {
243  Q_UNUSED(column)
244  Q_UNUSED(action)
245  if(!data->formats().contains("pintreemodel/item")) return false;
246 
247  QString type; int id;
248  auto encItem = data->data("pintreemodel/item");
249  QDataStream dataStream(&encItem, QIODevice::ReadOnly);
250  dataStream >> type >> id;
251  auto parentItem = static_cast<ModulePinsTreeItem*>(getItemFromIndex(parent));
252  // qDebug() << "type: " << type << ", id" << id << ", row: " << row;
253 
254  // construct a "drop-matrix" here, but only 4(5) things are NOT allowed (so check for these):
255  // 1: drop a pin on its OWN parent
256  // 3: drop a pingroup on/between pins
257  // 4: drop an item on itself
258  // 5: drop adjecent index to itself, must be at least 1 item apart
259  if(type == "group")
260  {
261  auto item = static_cast<ModulePinsTreeItem*>(mIdToGroupItem[id]);
262  if(parentItem)
263  {
264  if(item->itemType() == ModulePinsTreeItem::Pin || (item->itemType() == ModulePinsTreeItem::Group && row != -1) || item == parentItem)
265  return false;
266  }
267  else // here, only check for adjacent rows
268  {
269  auto itRow = item->getOwnRow();
270  if(itRow == row || ((itRow+1) == row))
271  return false;
272  }
273  }
274  if(type == "pin")
275  {
276  // perhaps check here that a pin can only be dropped between groups if its own group has size > 1?
277  // otherwise it does not make much sense...perhaps change this check
278  auto item = mIdToPinItem[id];
279  if((!parentItem && item->getParent()->getChildCount() == 1)
280  || (item->getParent() == parentItem && row == -1)
281  || item == parentItem )
282  // || (parentItem && (parentItem->itemType() == PortTreeItem::Pin)))
283  return false;
284  // case if one wants to drop between pins in same group, check if its not adjacent row (other cases are handled on case above
285  if(item->getParent() == parentItem)
286  {
287  auto itRow = item->getOwnRow();
288  if(itRow == row || ((itRow+1) == row))
289  return false;
290  }
291  }
292  return true;
293  }
294 
296  {
298  mModule = nullptr;
299  mNameToTreeItem.clear();
300  mIdToGroupItem.clear();
301  mIdToPinItem.clear();
302  }
303 
305  {
306  mModule = m;
307  beginResetModel();
308 
309  for(PinGroup<ModulePin>* pinGroup : m->get_pin_groups())
310  {
311  if(pinGroup->empty())
312  continue;
313 
314  auto pinGroupName = QString::fromStdString(pinGroup->get_name());
315  ModulePinsTreeItem* pinGroupItem = new ModulePinsTreeItem(ModulePinsTreeItem::Group, pinGroup->get_id(), pinGroupName, pinGroup->get_direction(),
316  pinGroup->get_type(), pinGroup->is_ascending() ? 0 : 1);
317  mIdToGroupItem.insert(pinGroup->get_id(), pinGroupItem);
318  for(ModulePin* pin : pinGroup->get_pins())
319  {
321  pin->get_id(),
322  QString::fromStdString(pin->get_name()),
323  pin->get_direction(),
324  pin->get_type(),
325  pin->get_group().second,
326  QString::fromStdString(pin->get_net()->get_name()));
327  pinGroupItem->appendChild(pinItem);
328  mNameToTreeItem.insert(QString::fromStdString(pin->get_name()), pinItem);
329  mIdToPinItem.insert(pin->get_id(), pinItem);
330  }
331  mNameToTreeItem.insert(pinGroupName, pinGroupItem);
332  mRootItem->appendChild(pinGroupItem);
333  }
334 
335 // Keep old code for the time being to review whether all cases are covered
336 //
337 // for (PinGroup<ModulePin>* pinGroup : m->get_pin_groups())
338 // {
339 // //ignore empty pingroups
340 // if (pinGroup->empty())
341 // continue;
342 
343 
344 // ModulePin* firstPin = pinGroup->get_pins().front();
345 // QString pinGroupName;
346 // QString pinGroupDirection = QString::fromStdString(enum_to_string(firstPin->get_direction()));
347 // QString pinGroupType = QString::fromStdString(enum_to_string(firstPin->get_type()));
348 // if (pinGroup->size() == 1)
349 // {
350 // pinGroupName = QString::fromStdString(firstPin->get_name());
351 // }
352 // else
353 // {
354 // pinGroupName = QString::fromStdString(pinGroup->get_name());
355 // }
356 
357 // TreeItem* pinGroupItem = new TreeItem(QList<QVariant>() << pinGroupName << pinGroupDirection << pinGroupType << "");
358 
359 // if (pinGroup->size() == 1)
360 // {
361 // pinGroupItem->setDataAtColumn(sNetColumn, QString::fromStdString(firstPin->get_net()->get_name()));
362 // pinGroupItem->setAdditionalData(keyType, QVariant::fromValue(itemType::pin));
363 // //since a single-pin pingroup represents the pin itself, take the pinid
364 // pinGroupItem->setAdditionalData(keyId, firstPin->get_id());
365 // mIdToPinItem.insert(firstPin->get_id(), pinGroupItem);
366 // }
367 // else
368 // {
369 // pinGroupItem->setAdditionalData(keyType, QVariant::fromValue(itemType::portMultiBit));
370 // pinGroupItem->setAdditionalData(keyId, pinGroup->get_id());
371 // mIdToGroupItem.insert(pinGroup->get_id(), pinGroupItem);
372 // for (ModulePin* pin : pinGroup->get_pins())
373 // {
374 // TreeItem* pinItem =
375 // new TreeItem(QList<QVariant>() << QString::fromStdString(pin->get_name()) << pinGroupDirection << pinGroupType << QString::fromStdString(pin->get_net()->get_name()));
376 // pinItem->setAdditionalData(keyType, QVariant::fromValue(itemType::pin));
377 // pinItem->setAdditionalData(keyId, pin->get_id());
378 // pinGroupItem->appendChild(pinItem);
379 // mNameToTreeItem.insert(QString::fromStdString(pin->get_name()), pinItem);
380 // mIdToPinItem.insert(pin->get_id(), pinItem);
381 // }
382 // }
383 // mRootItem->appendChild(pinGroupItem);
384 // mNameToTreeItem.insert(pinGroupName, pinGroupItem);
385 // }
386  endResetModel();
387 
388  Q_EMIT numberOfPortsChanged(m->get_pins().size());
389  }
390 
392  {
393  if (!mModule) //no current module = no represented net
394  return nullptr;
395 
396  if (item->itemType() == ModulePinsTreeItem::Group && item->getChildCount() > 1)
397  return nullptr;
398 
399  Module* m = gNetlist->get_module_by_id(mModule->get_id());
400  if (!m)
401  return nullptr;
402 
403  //std::string name = item->getData(sNameColumn).toString().toStdString();
404  if (auto* pin = m->get_pin_by_id(item->id()); pin != nullptr)
405  {
406  return pin->get_net();
407  }
408 
409  return nullptr;
410  }
411 
413  {
414  if (!mModule) return -1;
415  return mModule->get_id();
416  }
417 
419  {
420  static const QSet<PinEvent> groupEvents = { PinEvent::GroupCreate,
426  Q_UNUSED(pev);
427  Q_UNUSED(pgid);
428  if (m != mModule) return;
429 
430  // debug pingroups log_info("gui", "Handle pin_changed event {} ID={}", enum_to_string<PinEvent>(pev), pgid);
431  ModulePinsTreeItem* ptiPin = nullptr;
432  ModulePinsTreeItem* ptiGroup = nullptr;
433  const PinGroup<ModulePin>* pgroup = nullptr;
434  const ModulePin* pin = nullptr;
435  int pinRow = -1;
436 
437 
438  if (pev == PinEvent::PinDelete)
439  {
440  ptiPin = mIdToPinItem.value(pgid);
441  }
442 
443  if (groupEvents.contains(pev))
444  {
445  // group event
446  ptiGroup = mIdToGroupItem.value(pgid);
447  if (pev != PinEvent::GroupCreate && !ptiGroup)
448  {
449  log_warning("gui", "Cannot handle event for pin group ID={}, tree item does not exist.", pgid);
450  return;
451  }
452  if (pev != PinEvent::GroupDelete)
453  {
454  pgroup = m->get_pin_group_by_id(pgid);
455  if (!pgroup)
456  {
457  log_warning("gui", "Cannot handle event for pin group ID={}, no such group.", pgid);
458  return;
459  }
460  }
461  }
462  else
463  {
464  // pin event
465  ptiPin = mIdToPinItem.value(pgid);
466  if (pev != PinEvent::PinCreate && !ptiPin)
467  {
468  log_warning("gui", "Cannot handle event for pin ID={}, tree item does not exist.", pgid);
469  return;
470  }
471  if (pev != PinEvent::PinDelete)
472  {
473  pin = m->get_pin_by_id(pgid);
474  if (!pin)
475  {
476  log_warning("gui", "Cannot handle event for pin ID={}, no such pid.", pgid);
477  return;
478  }
479  auto pgPair = pin->get_group();
480  pgroup = pgPair.first;
481  pinRow = ActionPingroup::pinIndex2Row(pin,pgPair.second);
482  if (pgroup)
483  ptiGroup = mIdToGroupItem.value(pgroup->get_id());
484  }
485  }
486 
487  QModelIndex dataChangedIndex;
488 
489  switch (pev)
490  {
492  {
494  pgroup->get_id(),
495  QString::fromStdString(pgroup->get_name()),
496  pgroup->get_direction(),
497  pgroup->get_type(),
498  pgroup->is_ascending()?0:1);
499  mIdToGroupItem.insert(ptiGroup->id(), ptiGroup);
500  int inx = ActionPingroup::pinGroupIndex(m,pgroup);
501  insertItem(ptiGroup, mRootItem, inx);
502  break;
503  }
505  {
506  int inx = ActionPingroup::pinGroupIndex(m,pgroup);
507  removeItem(ptiGroup);
508  insertItem(ptiGroup, mRootItem, inx);
509  break;
510  }
512  ptiGroup->setName(QString::fromStdString(pgroup->get_name()));
513  dataChangedIndex = getIndexFromPinsItem(ptiGroup);
514  break;
516  ptiGroup->setPinType(pgroup->get_type());
517  dataChangedIndex = getIndexFromPinsItem(ptiGroup);
518  break;
520  ptiGroup->setPinDirection(pgroup->get_direction());
521  dataChangedIndex = getIndexFromPinsItem(ptiGroup);
522  break;
524  removeItem(ptiGroup);
525  delete ptiGroup;
526  break;
527  case PinEvent::PinCreate:
528  {
529  if (!pgroup || !ptiGroup)
530  {
531  log_warning("gui", "Cannot handle pin create event for pin ID={}, pin is not assigned to any group.", pgid);
532  return;
533  }
534  QString netName;
535  if (pin->get_net())
536  netName = QString::fromStdString(pin->get_net()->get_name());
538  pin->get_id(),
540  pin->get_direction(),
541  pin->get_type(),
542  pin->get_group().second,
543  netName);
544  mIdToPinItem.insert(ptiPin->id(), ptiPin);
545  insertItem(ptiPin, ptiGroup, pinRow);
546  updateGroupIndex(ptiGroup);
547  break;
548  }
550  {
551  if (!pgroup || !ptiGroup)
552  {
553  log_warning("gui", "Cannot handle pin reorder event for pin ID={}, pin is not assigned to any group.", pgid);
554  return;
555  }
556  removeItem(ptiPin);
557  insertItem(ptiPin, ptiGroup, pinRow);
558  updateGroupIndex(ptiGroup);
559  break;
560  }
562  {
563  if (!pgroup || !ptiGroup)
564  {
565  log_warning("gui", "Cannot handle pin assign event for pin ID={}, pin is not assigned to any group.", pgid);
566  return;
567  }
568  removeItem(ptiPin);
569  insertItem(ptiPin, ptiGroup, pinRow);
570 
571  // Unfortunately the event does not tell us where the pin was assigned previously. We have to update all group indices.
572  for (BaseTreeItem* bti : mRootItem->getChildren())
573  {
574  ModulePinsTreeItem* grpItem = static_cast<ModulePinsTreeItem*>(bti);
575  // check whether group still exists (might have been deleted when moving last pin)
576  if (mModule->get_pin_group_by_id(grpItem->id()))
577  updateGroupIndex(static_cast<ModulePinsTreeItem*>(grpItem));
578  }
579  break;
580  }
581  case PinEvent::PinRename:
582  ptiPin->setName(QString::fromStdString(pin->get_name()));
583  dataChangedIndex = getIndexFromPinsItem(ptiPin);
584  break;
586  ptiPin->setPinType(pin->get_type());
587  dataChangedIndex = getIndexFromPinsItem(ptiPin);
588  break;
590  ptiPin->setPinDirection(pin->get_direction());
591  dataChangedIndex = getIndexFromPinsItem(ptiPin);
592  break;
593  case PinEvent::PinDelete:
594  removeItem(ptiPin);
595  delete ptiPin;
596  break;
597  default:
598  break;
599  }
600 
601  if (dataChangedIndex.isValid())
602  {
603  QModelIndex inxLastCol = createIndex(dataChangedIndex.row(),columnCount()-1,dataChangedIndex.internalPointer());
604  Q_EMIT dataChanged(dataChangedIndex,inxLastCol);
605  }
606  }
607 
608  void ModulePinsTreeModel::dndGroupOnGroup(BaseTreeItem *droppedGroup, BaseTreeItem *onDroppedGroup, int row)
609  {
610  // SPECIFY: 1) create completely new group, all pins in that, delete old 2 groups
611  // 2) just add all pins from dropped group to "ondroppedgroup", then rename?
612 // InputDialog ipd("Name of new group", "Name of new group:", onDroppedGroup->getData(sNameColumn).toString());
613 // if(ipd.exec() == QDialog::Rejected) return false;
615  auto srcgroup = mModule->get_pin_group_by_id(static_cast<ModulePinsTreeItem*>(droppedGroup)->id());
616  for(const auto &pin : srcgroup->get_pins())
617  pins.append(pin->get_id());
618  if (pins.isEmpty()) return; // no pins to move
619 
620  auto tgtgroup = mModule->get_pin_group_by_id(static_cast<ModulePinsTreeItem*>(onDroppedGroup)->id());
621 
622  ActionPingroup* act = ActionPingroup::addPinsToExistingGroup(mModule,tgtgroup->get_id(),pins,row);
623  if (act) act->exec();
624 
625  // too keep the order, ActionAddItemsToObject cannot be executed with all pins, but a ComAction must be created
626  // with many ActionAddItemsToObject that contain a single pin each -> set destroys order of pins in source pingroup
627  }
628 
629  void ModulePinsTreeModel::dndGroupBetweenGroup(ModulePinsTreeItem *droppedGroup, int row)
630  {
631  int ownRow = droppedGroup->getOwnRow();
632  bool bottomEdge = row == mRootItem->getChildCount();
633  auto desiredIdx = bottomEdge ? row-1 : row;
634  if(ownRow < row && !bottomEdge) desiredIdx--;
635  ActionPingroup* act = new ActionPingroup(PinActionType::GroupMoveToRow,droppedGroup->id(),"",desiredIdx);
636  act->setObject(UserActionObject(mModule->get_id(),UserActionObjectType::Module));
637  act->exec();
638  }
639 
640  void ModulePinsTreeModel::dndPinOnGroup(ModulePinsTreeItem *droppedPin, BaseTreeItem *onDroppedGroup)
641  {
642  ActionPingroup* act = new ActionPingroup(PinActionType::PinAsignToGroup,droppedPin->id(),"",static_cast<ModulePinsTreeItem*>(onDroppedGroup)->id());
643  act->setObject(UserActionObject(mModule->get_id(),UserActionObjectType::Module));
644  act->exec();
645  }
646 
647  void ModulePinsTreeModel::dndPinBetweenPin(ModulePinsTreeItem *droppedPin, BaseTreeItem *onDroppedParent, int row)
648  {
649  int desiredIdx = row;
650  ActionPingroup* act = nullptr;
651  if(droppedPin->getParent() == onDroppedParent) // same group
652  {
653  int ownRow = droppedPin->getOwnRow();
654  bool bottomEdge = row == onDroppedParent->getChildCount();
655  desiredIdx = bottomEdge ? row-1 : row;
656  if(ownRow < row && !bottomEdge) desiredIdx--; // insert item here
657  act = new ActionPingroup(PinActionType::PinMoveToRow,droppedPin->id(),"",desiredIdx); // TODO : start_index, descending
658  }
659  else
660  {
661  act = ActionPingroup::addPinToExistingGroup(mModule,static_cast<ModulePinsTreeItem*>(onDroppedParent)->id(),droppedPin->id(),desiredIdx);
662  if (!act) return;
663  }
664  act->setObject(UserActionObject(mModule->get_id(),UserActionObjectType::Module));
665  act->exec();
666  }
667 
668  void ModulePinsTreeModel::dndPinBetweenGroup(ModulePinsTreeItem *droppedPin, int row)
669  {
670  // row is needed for when groups can change its order within the module
671  Q_UNUSED(row)
672 
673  auto pinToMove = mModule->get_pin_by_id(droppedPin->id());
674  if (!pinToMove) return;
675 
676  QString groupName = ActionPingroup::generateGroupName(mModule,pinToMove);
677 
678  ActionPingroup* act = ActionPingroup::addPinToNewGroup(mModule, groupName, droppedPin->id(),row);
679  act->exec();
680  }
681 
682  void ModulePinsTreeModel::updateGroupIndex(ModulePinsTreeItem* groupItem)
683  {
684  PinGroup<ModulePin>* pg = mModule->get_pin_group_by_id(groupItem->id());
685  Q_ASSERT(pg);
686  for (ModulePin* pin : pg->get_pins())
687  {
688  int inx = pg->get_index(pin).get();
689  ModulePinsTreeItem* pinItem = mIdToPinItem.value(pin->get_id());
690  Q_ASSERT(pinItem);
691  pinItem->setIndex(inx);
692  }
693  QModelIndex pi = getIndexFromPinsItem(groupItem);
694  QModelIndex i0 = index(0,0,pi);
695  QModelIndex i1 = index(groupItem->getChildCount()-1,4,pi);
696  Q_EMIT dataChanged(i0,i1);
697  }
698 
699  void ModulePinsTreeModel::insertItem(ModulePinsTreeItem* item, BaseTreeItem* parent, int index)
700  {
701  // fun fact: if an item is inserted above an item that is expanded, the tree collapses all indeces
703  parent->insertChild(index, item);
704  endInsertRows();
705  //mNameToTreeItem.insert(item->getData(sNameColumn).toString(), item);
706  item->itemType() == ModulePinsTreeItem::Pin ? mIdToPinItem.insert(item->id(), item) : mIdToGroupItem.insert(item->id(), item);
707  //mIdToPinItem.insert(getIdOfItem(item), item);
708  }
709 
710  void ModulePinsTreeModel::removeItem(ModulePinsTreeItem* item)
711  {
712  auto itOrphan = mOrphanedItem.find(item);
713  if (itOrphan != mOrphanedItem.end())
714  {
715  // already orphaned and not part of the tree
716  mOrphanedItem.erase(itOrphan);
717  }
718  else
719  {
720  beginRemoveRows(parent(getIndexFromPinsItem(item)), item->getOwnRow(), item->getOwnRow());
721  item->getParent()->removeChild(item);
722  endRemoveRows();
723  }
724  //mNameToTreeItem.remove(item->getData(sNameColumn).toString());
725  //for now, only ids of pin-items (since these functions are only relevant for dnd)
726  if (item->itemType() == ModulePinsTreeItem::Pin)
727  mIdToPinItem.remove(item->id());
728  else
729  {
730  for (BaseTreeItem* bti : item->getChildren())
731  {
732  mOrphanedItem.insert(static_cast<ModulePinsTreeItem*>(bti));
733  item->removeChild(bti);
734  }
735  mIdToGroupItem.remove(item->id());
736  }
737  //mIdToPinItem.remove(getIdOfItem(item));
738  //delete item;
739  }
740 
741  void ModulePinsTreeModel::dumpModel(const char* msg) const
742  {
743  std::cerr << msg << " \t Pins:";
744  for (int i : mIdToPinItem.keys()) std::cerr << " " << i;
745  std::cerr << " \t Grps:";
746  for (int i : mIdToGroupItem.keys()) std::cerr << " " << i;
747  std::cerr << std::endl;
748  for (const BaseTreeItem* bti : mRootItem->getChildren())
749  {
750  const ModulePinsTreeItem* mpti = static_cast<const ModulePinsTreeItem*>(bti);
751  std::cerr << mpti->id() << " <" << mpti->name().toStdString() << ">\n";
752  for (const BaseTreeItem* cti : mpti->getChildren())
753  {
754  const ModulePinsTreeItem* mptpin = static_cast<const ModulePinsTreeItem*>(cti);
755  std::cerr << " " << mptpin->id() << " <" << mptpin->name().toStdString() << "> \t" << mptpin->getData(2).toString().toStdString() << " \t " <<
756  mptpin->getData(4).toString().toStdString() << "\n";
757  }
758  }
759  std::cerr << "-------------" << std::endl;
760  }
761 
762 } // namespace hal
Pingroup user actions.
static ActionPingroup * addPinToNewGroup(const Module *m, const QString &name, u32 pinId, int grpRow=-1)
static QString generateGroupName(const Module *mod, const ModulePin *pin)
static ActionPingroup * addPinToExistingGroup(const Module *m, u32 grpId, u32 pinId, int pinRow=-1)
static ActionPingroup * addPinsToExistingGroup(const Module *m, u32 grpId, QList< u32 > pinIds, int pinRow=-1)
static int pinGroupIndex(const Module *mod, const PinGroup< ModulePin > *pgrp)
static int pinIndex2Row(const ModulePin *pin, int index)
bool exec() override
const std::string & get_name() const
Definition: base_pin.h:108
u32 get_id() const
Definition: base_pin.h:88
PinType get_type() const
Definition: base_pin.h:148
const std::pair< PinGroup< T > *, i32 > & get_group() const
Definition: base_pin.h:158
PinDirection get_direction() const
Definition: base_pin.h:128
(Future) Base class for all tree models related to the details widget.
virtual QList< BaseTreeItem * > getChildren() const
virtual BaseTreeItem * getParent() const
virtual int getChildCount() const
virtual void appendChild(BaseTreeItem *child)
virtual int getOwnRow()
The BaseTreeModel implements generic standard functions of a tree model.
QModelIndex getIndexFromItem(BaseTreeItem *item) const
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const override
RootTreeItem * mRootItem
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
virtual void clear()
virtual Qt::ItemFlags flags(const QModelIndex &index) const override
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void setHeaderLabels(const QStringList &label)
BaseTreeItem * getItemFromIndex(QModelIndex index) const
std::vector< ModulePin * > get_pins(const std::function< bool(ModulePin *)> &filter=nullptr) const
Definition: module.cpp:873
ModulePin * get_pin_by_id(const u32 id) const
Definition: module.cpp:985
std::vector< PinGroup< ModulePin > * > get_pin_groups(const std::function< bool(PinGroup< ModulePin > *)> &filter=nullptr) const
Definition: module.cpp:964
PinGroup< ModulePin > * get_pin_group_by_id(const u32 id) const
Definition: module.cpp:1036
u32 get_id() const
Definition: module.cpp:82
Net * get_net() const
Definition: module_pin.cpp:19
void setPinType(PinType ptype)
void setName(const QString &nam)
QVariant getData(int column) const override
void setPinDirection(PinDirection dir)
int getColumnCount() const override
void setData(QList< QVariant > data) override
void setDataAtColumn(int column, QVariant &data) override
void appendData(QVariant data) override
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override
ModulePinsTreeModel(QObject *parent=nullptr)
QStringList mimeTypes() const override
QMimeData * mimeData(const QModelIndexList &indexes) const override
void handleModulePortsChanged(Module *m, PinEvent pev, u32 pgid)
Qt::ItemFlags flags(const QModelIndex &index) const override
Net * getNetFromItem(ModulePinsTreeItem *item)
void numberOfPortsChanged(const int newNumber)
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
Definition: net.h:58
const std::string & get_name() const
Definition: net.cpp:98
Module * get_module_by_id(u32 module_id) const
Definition: netlist.cpp:613
void modulePortsChanged(Module *m, PinEvent pev, u32 pgid) const
u32 get_id() const
Definition: pin_group.h:130
const std::string & get_name() const
Definition: pin_group.h:150
bool is_ascending() const
Definition: pin_group.h:273
PinDirection get_direction() const
Definition: pin_group.h:190
PinType get_type() const
Definition: pin_group.h:170
static QString pyCodeModulePinGroup(u32 moduleId, u32 groupId)
static QString pyCodeModulePinById(u32 moduleId, u32 pinId)
#define log_warning(channel,...)
Definition: log.h:76
action
Definition: control.py:16
PinDirection
Definition: pin_direction.h:36
PinEvent
Definition: pin_event.h:42
@ PinTypeChange
pin renamed
@ GroupReorder
changed PinDirection attribute of group (like input)
@ PinDirChange
changed PinType attribute of pin (like data)
@ PinCreate
moved group to a new position within containing module
@ GroupTypeChange
pin group renamed
@ PinRename
pin assigned to new group
@ PinAssignToGroup
new pin created
@ PinDelete
moved pin to a new position within containing group
@ GroupRename
new pin group created
@ GroupDelete
pin deleted
@ GroupDirChange
changed PinType attribute of group (like data)
@ PinReorder
changed PinDirection attribute of pin (like input)
Netlist * gNetlist
Definition: plugin_gui.cpp:80
NetlistRelay * gNetlistRelay
Definition: plugin_gui.cpp:81
PinType
Definition: pin_type.h:36
std::string enum_to_string(T e)
Definition: enums.h:52
quint32 u32
PinType type
std::vector< PinInformation > pins
i32 id
void beginInsertRows(const QModelIndex &parent, int first, int last)
void beginRemoveRows(const QModelIndex &parent, int first, int last)
QModelIndex createIndex(int row, int column, void *ptr) const const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles)
void * internalPointer() const const
bool isValid() const const
int row() 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
QString fromStdString(const std::string &str)
DropAction
typedef ItemFlags