HAL
module_pins_tree.cpp
Go to the documentation of this file.
2 
3 #include "gui/gui_globals.h"
12 
13 #include <QApplication>
14 #include <QClipboard>
15 #include <QHeaderView>
16 #include <QList>
17 #include <QMenu>
18 #include <QMessageBox>
19 #include <QQueue>
20 #include <QSet>
21 
22 namespace hal
23 {
24  ModulePinsTree::ModulePinsTree(QWidget* parent) : QTreeView(parent), mPortModel(new ModulePinsTreeModel(this)), mModuleID(-1)
25  {
28  //setSelectionMode(QAbstractItemView::NoSelection);
30  //setSelectionMode(QAbstractItemView::SingleSelection);
34  setModel(mPortModel);
35 
36  setDragDropMode(DragDropMode::DragDrop);
37  setDragEnabled(true);
38  setAcceptDrops(true);
39  viewport()->setAcceptDrops(true);
41 
42  //connections
44  connect(mPortModel, &ModulePinsTreeModel::numberOfPortsChanged, this, &ModulePinsTree::handleNumberOfPortsChanged);
45  }
46 
48  {
49  Module* m = gNetlist->get_module_by_id(moduleID);
50  if (!m)
51  return;
52 
53  mPortModel->clear();
54  mPortModel->setModule(m);
55  mModuleID = moduleID;
56  }
57 
59  {
60  if (!m)
61  return;
62 
63  setModule(m->get_id());
64  }
65 
67  {
68  mPortModel->clear();
69  mModuleID = -1;
70  }
71 
73  {
74  return mModuleID;
75  }
76 
78  {
79  QModelIndex clickedIndex = indexAt(pos);
80  if (!clickedIndex.isValid())
81  return;
82 
83  //all relevant information
84  ModulePinsTreeItem* clickedItem = static_cast<ModulePinsTreeItem*>(mPortModel->getItemFromIndex(clickedIndex));
85  Net* n = mPortModel->getNetFromItem(clickedItem);
87  u32 modId = mPortModel->getRepresentedModuleId();
88  auto mod = gNetlist->get_module_by_id(modId);
89  QList<BaseTreeItem*> selectedPins;
90  std::pair<bool, int> sameGroup;
91  bool onlyPins;
92  std::tie(selectedPins, sameGroup, onlyPins) = getSelectedPins();
93  int itemId = clickedItem->id();
94  QMenu menu;
95 
96  //shared plaintext entries: NAME, DIRECTION, TYPE (shared with pins and groups)
97  menu.addAction("Name to clipboard", [clickedItem]() { QApplication::clipboard()->setText(clickedItem->getData(ModulePinsTreeModel::sNameColumn).toString()); });
98  menu.addAction("Direction to clipboard", [clickedItem]() { QApplication::clipboard()->setText(clickedItem->getData(ModulePinsTreeModel::sDirectionColumn).toString()); });
99  menu.addAction("Type to clipboard", [clickedItem]() { QApplication::clipboard()->setText(clickedItem->getData(ModulePinsTreeModel::sTypeColumn).toString()); });
100 
101  menu.addSection("Misc");
102 
103  //shared context menu entry to add to existing groups
104  bool addToExistingActionPossible = true;
105 // for (auto pingroup : mod->get_pin_groups())
106 // {
107 // if (pingroup->size() > 1) //at least one pingroup should have at least 2 items
108 // {
109 // addToExistingActionPossible = true;
110 // break;
111 // }
112 // }
113  if (addToExistingActionPossible)
114  {
115  menu.addAction("Add selection to existing pin group", [selectedPins, mod]() {
116  PingroupSelectorDialog psd("Pingroup selector", "Select pingroup", mod, false);
117  if (psd.exec() == QDialog::Accepted)
118  {
120  auto* pinGroup = mod->get_pin_group_by_id(psd.getSelectedGroupId());
121  if (pinGroup == nullptr)
122  return;
123  for (auto item : selectedPins)
124  {
125  auto* pin = mod->get_pin_by_id(static_cast<ModulePinsTreeItem*>(item)->id());
126  if (pin == nullptr)
127  return;
128  pins.append(pin->get_id());
129  }
130  ActionPingroup* act = ActionPingroup::addPinsToExistingGroup(mod,pinGroup->get_id(),pins);
131  if (act) act->exec();
132  }
133  });
134  }
135 
136  if (clickedItem->itemType() == ModulePinsTreeItem::Group) //group specific context, own helper function? (returns at the end)
137  {
138  menu.addAction("Change name", [itemId, mod, name]() {
139  PinGroup<ModulePin>* pg = mod->get_pin_group_by_id(itemId);
140  if (pg == nullptr) return;
141 
142  InputDialog ipd("Change pin group name", "New group name", name);
143  if (ipd.exec() == QDialog::Accepted)
144  {
145  if (ipd.textValue().isEmpty())
146  return;
147 
150  act->exec();
151  }
152  });
153 
154  menu.addAction("Change type", [itemId, mod, name]() {
155  PinGroup<ModulePin>* pg = mod->get_pin_group_by_id(itemId);
156  if (pg == nullptr) return;
157 
158  QStringList types;
159  for (auto const& [k, v] : EnumStrings<PinType>::data)
160  types << QString::fromStdString(v);
161 
162  ComboboxDialog cbd("Change type", "Select type for pin group " + name, types);
163 
164  if (cbd.exec() == QDialog::Accepted)
165  {
166  PinType ptype = enum_from_string<PinType>(cbd.textValue().toStdString(),PinType::none);
167  ActionPingroup* act = ActionPingroup::changePinGroupType(mod,itemId,(int)ptype);
168  if (act) act->exec();
169  }
170  });
171  menu.addAction("Toggle ascending/descending", [itemId, mod](){
173  if (act) act->exec();
174  });
175  menu.addAction("Autmatically rename pins", [itemId, mod](){
177  if (act) act->exec();
178  });
179  menu.addAction("Delete pin group", [itemId, mod]() {
180  auto* pinGroup = mod->get_pin_group_by_id(itemId);
181  if (pinGroup != nullptr)
182  {
184  if (act) act->exec();
185  }
186  });
187 
188  if (selectionModel()->selectedRows().size() > 1)
189  appendMultiSelectionEntries(menu, modId);
190 
191  menu.addSection("Python");
192  menu.addAction(QIcon(":/icons/python"), "Get pin group", [modId, itemId]() { QApplication::clipboard()->setText(PyCodeProvider::pyCodeModulePinGroup(modId, itemId)); });
193  menu.move(mapToGlobal(pos));
194  menu.exec();
195  return;
196  }
197 
198  //menu.addSection("Misc");
199  if (n) //should never be nullptr, but you never know
200  {
201  menu.addAction("Change name", [mod, name, itemId]() {
202  InputDialog ipd("Change pin name", "New pin name", name);
203  if (ipd.exec() == QDialog::Accepted)
204  {
205  if (ipd.textValue().isEmpty())
206  return;
207  auto* pin = mod->get_pin_by_id(itemId);
208  if (pin != nullptr)
209  {
210  ActionPingroup* act = new ActionPingroup(PinActionType::PinRename,pin->get_id(),ipd.textValue());
212  act->exec();
213  }
214  }
215  });
216 
217  menu.addAction("Change type", [mod, name, itemId]() {
218  auto* pin = mod->get_pin_by_id(itemId);
219  if (pin == nullptr)
220  return;
221 
222  QStringList types;
223  for (auto const& [k, v] : EnumStrings<PinType>::data)
224  types << QString::fromStdString(v);
225 
226  ComboboxDialog cbd("Pin Types", "Select pin type", types);
227 
228  if (cbd.exec() == QDialog::Accepted)
229  {
230  PinType ptype = enum_from_string<PinType>(cbd.textValue().toStdString(),PinType::none);
231 
232  ActionPingroup* act = new ActionPingroup(PinActionType::PinTypeChange,pin->get_id(),"",(int)ptype);
234  act->exec();
235  }
236  });
237  menu.addAction("Add net to current selection", [this, n]() {
238  gSelectionRelay->addNet(n->get_id());
240  });
241  menu.addAction("Set net as current selection", [this, n]() {
243  gSelectionRelay->addNet(n->get_id());
245  });
246  }
247  //can be both single(simple right-click, no real selection) and multi-selection
248  if (sameGroup.first && mod->get_pin_group_by_id(sameGroup.second)->size() > 1)
249  {
250  menu.addAction("Remove selection from group", [selectedPins, mod /*, sameGroup*/]() {
252  for (auto item : selectedPins)
253  pins.append(static_cast<ModulePinsTreeItem*>(item)->id());
254 
256  if (act) act->exec();
257  });
258  }
259 
260  //multi-selection (part of misc)
261  if (selectionModel()->selectedRows().size() > 1)
262  appendMultiSelectionEntries(menu, modId);
263 
264  menu.addSection("Python");
265  if(clickedItem->itemType()==ModulePinsTreeItem::Pin)
266  menu.addAction(QIcon(":/icons/python"), "Get pin", [modId, itemId]() { QApplication::clipboard()->setText(PyCodeProvider::pyCodeModulePinById(modId, itemId)); });
267  else
268  menu.addAction(QIcon(":/icons/python"), "Get group", [modId, itemId]() { QApplication::clipboard()->setText(PyCodeProvider::pyCodeModulePinGroup(modId, itemId)); });
269 
270  menu.move(mapToGlobal(pos));
271  menu.exec();
272  }
273 
274  void ModulePinsTree::handleNumberOfPortsChanged(int newNumberPorts)
275  {
276  Q_EMIT updateText(QString("Pins (%1)").arg(newNumberPorts));
277  }
278 
279  void ModulePinsTree::appendMultiSelectionEntries(QMenu& menu, int modId)
280  {
281  QList<BaseTreeItem*> selectedPins;
282  std::pair<bool, int> sameGroup;
283  bool onlyPins;
284  std::tie(selectedPins, sameGroup, onlyPins) = getSelectedPins();
285  if (selectedPins.size() > 1)
286  {
287  menu.addAction("Add objects to new pin group", [selectedPins, modId]() {
288  InputDialog ipd("Pingroup name", "New pingroup name", "ExampleName");
289  if (ipd.exec() == QDialog::Accepted && !ipd.textValue().isEmpty())
290  {
292  Module* mod = gNetlist->get_module_by_id(modId);
293  for (auto item : selectedPins)
294  {
295  auto* pin = mod->get_pin_by_id(static_cast<ModulePinsTreeItem*>(item)->id());
296  if (pin == nullptr)
297  return;
298  pins.append(pin->get_id());
299  }
300 
301  ActionPingroup* act = ActionPingroup::addPinsToNewGroup(mod,ipd.textValue(),pins);
302  if (act) act->exec();
303  }
304  });
305  }
306  }
307 
308  std::tuple<QList<BaseTreeItem*>, std::pair<bool, int>, bool> ModulePinsTree::getSelectedPins()
309  {
310  QList<BaseTreeItem*> selectedPins; //ordered
311  QSet<BaseTreeItem*> alreadyProcessedPins; //only for performance purposes
312  bool sameGroup = true;
313  bool onlyPins = true;
314  int groupId = -1;
315  for (auto index : selectionModel()->selectedRows())
316  {
317  ModulePinsTreeItem* item = static_cast<ModulePinsTreeItem*>(mPortModel->getItemFromIndex(index));
318  if (item->itemType() == ModulePinsTreeItem::Pin)
319  {
320  if (!alreadyProcessedPins.contains(item))
321  {
322  selectedPins.append(item);
323  alreadyProcessedPins.insert(item);
324  }
325  }
326  else if (item->itemType() == ModulePinsTreeItem::Group)
327  {
328  onlyPins = false;
329  for (auto pinItem : item->getChildren())
330  {
331  if (!alreadyProcessedPins.contains(pinItem))
332  {
333  selectedPins.append(pinItem);
334  alreadyProcessedPins.insert(pinItem);
335  }
336  }
337  }
338  }
339  //Check if all pins are from the same group (if no pin is selected it is from the same group)
340  if (!selectedPins.isEmpty())
341  {
342  auto mod = gNetlist->get_module_by_id(mModuleID);
343  auto* firstPin = mod->get_pin_by_id(static_cast<ModulePinsTreeItem*>(selectedPins.front())->id());
344  groupId = firstPin->get_group().first->get_id();
345  for (auto pinTreeItem : selectedPins)
346  {
347  auto pin = mod->get_pin_by_id(static_cast<ModulePinsTreeItem*>(pinTreeItem)->id());
348  if (groupId != (int)pin->get_group().first->get_id())
349  {
350  sameGroup = false;
351  break;
352  }
353  }
354  groupId = sameGroup ? groupId : -1;
355  }
356  return std::make_tuple(selectedPins, std::make_pair(sameGroup, groupId), onlyPins);
357  }
358 
359 } // namespace hal
Pingroup user actions.
static ActionPingroup * deletePinGroup(const Module *m, u32 grpId)
static ActionPingroup * addPinsToExistingGroup(const Module *m, u32 grpId, QList< u32 > pinIds, int pinRow=-1)
static ActionPingroup * automaticallyRenamePins(const Module *m, u32 grpId)
static ActionPingroup * toggleAscendingGroup(const Module *m, u32 grpId)
static ActionPingroup * addPinsToNewGroup(const Module *m, const QString &name, QList< u32 > pinIds, int grpRow=-1)
static ActionPingroup * removePinsFromGroup(const Module *m, QList< u32 > pinIds)
bool exec() override
static ActionPingroup * changePinGroupType(const Module *m, u32 grpId, int ptype)
const std::pair< PinGroup< T > *, i32 > & get_group() const
Definition: base_pin.h:158
BaseTreeItem * getItemFromIndex(QModelIndex index) const
QString textValue() const
Generic input dialog for user input.
Definition: input_dialog.h:51
QString textValue() const
ModulePin * get_pin_by_id(const u32 id) const
Definition: module.cpp:985
u32 get_id() const
Definition: module.cpp:82
void updateText(const QString &newHeadline)
void setModule(u32 moduleID)
void handleContextMenuRequested(const QPoint &pos)
ModulePinsTree(QWidget *parent=nullptr)
QVariant getData(int column) const override
A model to represent the ports of a module.
Net * getNetFromItem(ModulePinsTreeItem *item)
void numberOfPortsChanged(const int newNumber)
Definition: net.h:58
Module * get_module_by_id(u32 module_id) const
Definition: netlist.cpp:613
static QString pyCodeModulePinGroup(u32 moduleId, u32 groupId)
static QString pyCodeModulePinById(u32 moduleId, u32 pinId)
void relaySelectionChanged(void *sender)
virtual void setObject(const UserActionObject &obj)
Definition: user_action.cpp:32
The UserActionObject class represents a single object used in UserAction.
SelectionRelay * gSelectionRelay
Definition: plugin_gui.cpp:83
Netlist * gNetlist
Definition: plugin_gui.cpp:80
PinType
Definition: pin_type.h:36
n
Definition: test.py:6
quint32 u32
std::vector< PinInformation > pins
std::string name
void setDragDropMode(QAbstractItemView::DragDropMode behavior)
void setDragEnabled(bool enable)
void setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)
void setSelectionMode(QAbstractItemView::SelectionMode mode)
QItemSelectionModel * selectionModel() const const
void setDropIndicatorShown(bool enable)
QWidget * viewport() const const
void setText(const QString &text, QClipboard::Mode mode)
virtual int exec()
QClipboard * clipboard()
void setStretchLastSection(bool stretch)
QModelIndexList selectedRows(int column) const const
void append(const T &value)
T & front()
bool isEmpty() const const
int size() const const
QAction * addAction(const QString &text)
QAction * addSection(const QString &text)
QAction * exec()
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)
bool contains(const T &value) const const
QSet::iterator insert(const T &value)
QString fromStdString(const std::string &str)
bool isEmpty() const const
std::string toStdString() const const
CustomContextMenu
QHeaderView * header() const const
virtual QModelIndex indexAt(const QPoint &point) const const override
virtual void setModel(QAbstractItemModel *model) override
QString toString() const const
void setAcceptDrops(bool on)
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
void customContextMenuRequested(const QPoint &pos)
void setFocusPolicy(Qt::FocusPolicy policy)
QPoint mapToGlobal(const QPoint &pos) const const
void move(int x, int y)
void setSizePolicy(QSizePolicy)