HAL
module_ports_tree.cpp
Go to the documentation of this file.
2 
3 #include "gui/gui_globals.h"
20 
21 #include <QApplication>
22 #include <QClipboard>
23 #include <QHeaderView>
24 #include <QList>
25 #include <QMenu>
26 #include <QMessageBox>
27 #include <QQueue>
28 #include <QSet>
29 
30 namespace hal
31 {
32  ModulePinsTree::ModulePinsTree(QWidget* parent) : QTreeView(parent), mPortModel(new ModulePinsTreeModel(this)), mModuleID(-1)
33  {
36  //setSelectionMode(QAbstractItemView::NoSelection);
38  //setSelectionMode(QAbstractItemView::SingleSelection);
42  setModel(mPortModel);
43 
44  setDragDropMode(DragDropMode::DragDrop);
45  setDragEnabled(true);
46  setAcceptDrops(true);
47  viewport()->setAcceptDrops(true);
49 
50  //connections
52  connect(mPortModel, &ModulePinsTreeModel::numberOfPortsChanged, this, &ModulePinsTree::handleNumberOfPortsChanged);
53  }
54 
56  {
57  Module* m = gNetlist->get_module_by_id(moduleID);
58  if (!m)
59  return;
60 
61  mPortModel->setModule(m);
62  mModuleID = moduleID;
63  }
64 
66  {
67  if (!m)
68  return;
69 
70  setModule(m->get_id());
71  }
72 
74  {
75  mPortModel->clear();
76  mModuleID = -1;
77  }
78 
80  {
81  return mModuleID;
82  }
83 
85  {
86  QModelIndex clickedIndex = indexAt(pos);
87  if (!clickedIndex.isValid())
88  return;
89 
90  //all relevant information
91  PortTreeItem* clickedItem = static_cast<PortTreeItem*>(mPortModel->getItemFromIndex(clickedIndex));
92  Net* n = mPortModel->getNetFromItem(clickedItem);
94  u32 modId = mPortModel->getRepresentedModuleId();
95  auto mod = gNetlist->get_module_by_id(modId);
96  QList<BaseTreeItem*> selectedPins;
97  std::pair<bool, int> sameGroup;
98  bool onlyPins;
99  std::tie(selectedPins, sameGroup, onlyPins) = getSelectedPins();
100  int itemId = clickedItem->id();
101  QMenu menu;
102 
103  //shared plaintext entries: NAME, DIRECTION, TYPE (shared with pins and groups)
104  menu.addAction("Name to clipboard", [clickedItem]() { QApplication::clipboard()->setText(clickedItem->getData(ModulePinsTreeModel::sNameColumn).toString()); });
105  menu.addAction("Direction to clipboard", [clickedItem]() { QApplication::clipboard()->setText(clickedItem->getData(ModulePinsTreeModel::sDirectionColumn).toString()); });
106  menu.addAction("Type to clipboard", [clickedItem]() { QApplication::clipboard()->setText(clickedItem->getData(ModulePinsTreeModel::sTypeColumn).toString()); });
107 
108  menu.addSection("Misc");
109 
110  //shared context menu entry to add to existing groups
111  bool addToExistingActionPossible = true;
112 // for (auto pingroup : mod->get_pin_groups())
113 // {
114 // if (pingroup->size() > 1) //at least one pingroup should have at least 2 items
115 // {
116 // addToExistingActionPossible = true;
117 // break;
118 // }
119 // }
120  if (addToExistingActionPossible)
121  {
122  menu.addAction("Add selection to existing pin group", [selectedPins, mod]() {
123  PingroupSelectorDialog psd("Pingroup selector", "Select pingroup", mod, false);
124  if (psd.exec() == QDialog::Accepted)
125  {
127  auto* pinGroup = mod->get_pin_group_by_id(psd.getSelectedGroupId());
128  if (pinGroup == nullptr)
129  return;
130  for (auto item : selectedPins)
131  {
132  auto* pin = mod->get_pin_by_id(static_cast<PortTreeItem*>(item)->id());
133  if (pin == nullptr)
134  return;
135  pins.append(pin->get_id());
136  }
137  ActionPingroup* act = ActionPingroup::addPinsToExistingGroup(mod,pinGroup->get_id(),pins);
138  if (act) act->exec();
139  }
140  });
141  }
142 
143  if (clickedItem->itemType() == PortTreeItem::Group) //group specific context, own helper function? (returns at the end)
144  {
145  menu.addAction("Change name", [name, modId, itemId]() {
146  InputDialog ipd("Change pin group name", "New group name", name);
147  if (ipd.exec() == QDialog::Accepted)
148  {
149  if (ipd.textValue().isEmpty())
150  return;
151  auto* group = gNetlist->get_module_by_id(modId)->get_pin_group_by_id(itemId);
152  if (group != nullptr)
153  {
156  act->exec();
157  }
158  }
159  });
160  menu.addAction("Delete pin group", [itemId, mod]() {
161  auto* pinGroup = mod->get_pin_group_by_id(itemId);
162  if (pinGroup != nullptr)
163  {
165  if (act) act->exec();
166  }
167  });
168 
169  if (selectionModel()->selectedRows().size() > 1)
170  appendMultiSelectionEntries(menu, modId);
171 
172  menu.addSection("Python");
173  menu.addAction(QIcon(":/icons/python"), "Get pin group", [modId, itemId]() { QApplication::clipboard()->setText(PyCodeProvider::pyCodeModulePinGroup(modId, itemId)); });
174  menu.move(mapToGlobal(pos));
175  menu.exec();
176  return;
177  }
178 
179  //menu.addSection("Misc");
180  if (n) //should never be nullptr, but you never know
181  {
182  menu.addAction("Change name", [mod, name, itemId]() {
183  InputDialog ipd("Change pin name", "New pin name", name);
184  if (ipd.exec() == QDialog::Accepted)
185  {
186  if (ipd.textValue().isEmpty())
187  return;
188  auto* pin = mod->get_pin_by_id(itemId);
189  if (pin != nullptr)
190  {
191  ActionPingroup* act = new ActionPingroup(PinActionType::PinRename,pin->get_id(),ipd.textValue());
193  act->exec();
194  }
195  }
196  });
197 
198  menu.addAction("Change type", [mod, name, itemId]() {
199  auto* pin = mod->get_pin_by_id(itemId);
200  if (pin == nullptr)
201  return;
202 
203  QStringList types;
204  for (auto const& [k, v] : EnumStrings<PinType>::data)
205  types << QString::fromStdString(v);
206 
207  ComboboxDialog cbd("Pin Types", "Select pin type", types);
208 
209  if (cbd.exec() == QDialog::Accepted)
210  {
211  PinType ptype = enum_from_string<PinType>(cbd.textValue().toStdString(),PinType::none);
212 
213  ActionPingroup* act = new ActionPingroup(PinActionType::PinTypeChange,pin->get_id(),"",(int)ptype);
215  act->exec();
216  }
217  });
218  menu.addAction("Add net to current selection", [this, n]() {
219  gSelectionRelay->addNet(n->get_id());
221  });
222  menu.addAction("Set net as current selection", [this, n]() {
224  gSelectionRelay->addNet(n->get_id());
226  });
227  }
228  //can be both single(simple right-click, no real selection) and multi-selection
229  if (sameGroup.first && mod->get_pin_group_by_id(sameGroup.second)->size() > 1)
230  {
231  menu.addAction("Remove selection from group", [selectedPins, mod /*, sameGroup*/]() {
233  for (auto item : selectedPins)
234  pins.append(static_cast<PortTreeItem*>(item)->id());
235 
237  if (act) act->exec();
238  });
239  }
240 
241  //multi-selection (part of misc)
242  if (selectionModel()->selectedRows().size() > 1)
243  appendMultiSelectionEntries(menu, modId);
244 
245  menu.addSection("Python");
246  if(clickedItem->itemType()==PortTreeItem::Pin)
247  menu.addAction(QIcon(":/icons/python"), "Get pin", [modId, itemId]() { QApplication::clipboard()->setText(PyCodeProvider::pyCodeModulePinById(modId, itemId)); });
248  else
249  menu.addAction(QIcon(":/icons/python"), "Get group", [modId, itemId]() { QApplication::clipboard()->setText(PyCodeProvider::pyCodeModulePinGroup(modId, itemId)); });
250 
251  menu.move(mapToGlobal(pos));
252  menu.exec();
253  }
254 
255  void ModulePinsTree::handleNumberOfPortsChanged(int newNumberPorts)
256  {
257  Q_EMIT updateText(QString("Pins (%1)").arg(newNumberPorts));
258  }
259 
260  void ModulePinsTree::appendMultiSelectionEntries(QMenu& menu, int modId)
261  {
262  QList<BaseTreeItem*> selectedPins;
263  std::pair<bool, int> sameGroup;
264  bool onlyPins;
265  std::tie(selectedPins, sameGroup, onlyPins) = getSelectedPins();
266  if (selectedPins.size() > 1)
267  {
268  menu.addAction("Add objects to new pin group", [selectedPins, modId]() {
269  InputDialog ipd("Pingroup name", "New pingroup name", "ExampleName");
270  if (ipd.exec() == QDialog::Accepted && !ipd.textValue().isEmpty())
271  {
273  Module* mod = gNetlist->get_module_by_id(modId);
274  for (auto item : selectedPins)
275  {
276  auto* pin = mod->get_pin_by_id(static_cast<PortTreeItem*>(item)->id());
277  if (pin == nullptr)
278  return;
279  pins.append(pin->get_id());
280  }
281 
282  ActionPingroup* act = ActionPingroup::addPinsToNewGroup(mod,ipd.textValue(),pins);
283  if (act) act->exec();
284  }
285  });
286  }
287  }
288 
289  std::tuple<QList<BaseTreeItem*>, std::pair<bool, int>, bool> ModulePinsTree::getSelectedPins()
290  {
291  QList<BaseTreeItem*> selectedPins; //ordered
292  QSet<BaseTreeItem*> alreadyProcessedPins; //only for performance purposes
293  bool sameGroup = true;
294  bool onlyPins = true;
295  int groupId = -1;
296  for (auto index : selectionModel()->selectedRows())
297  {
298  PortTreeItem* item = static_cast<PortTreeItem*>(mPortModel->getItemFromIndex(index));
299  if (item->itemType() == PortTreeItem::Pin)
300  {
301  if (!alreadyProcessedPins.contains(item))
302  {
303  selectedPins.append(item);
304  alreadyProcessedPins.insert(item);
305  }
306  }
307  else if (item->itemType() == PortTreeItem::Group)
308  {
309  onlyPins = false;
310  for (auto pinItem : item->getChildren())
311  {
312  if (!alreadyProcessedPins.contains(pinItem))
313  {
314  selectedPins.append(pinItem);
315  alreadyProcessedPins.insert(pinItem);
316  }
317  }
318  }
319  }
320  //Check if all pins are from the same group (if no pin is selected it is from the same group)
321  if (!selectedPins.isEmpty())
322  {
323  auto mod = gNetlist->get_module_by_id(mModuleID);
324  auto* firstPin = mod->get_pin_by_id(static_cast<PortTreeItem*>(selectedPins.front())->id());
325  groupId = firstPin->get_group().first->get_id();
326  for (auto pinTreeItem : selectedPins)
327  {
328  auto pin = mod->get_pin_by_id(static_cast<PortTreeItem*>(pinTreeItem)->id());
329  if (groupId != (int)pin->get_group().first->get_id())
330  {
331  sameGroup = false;
332  break;
333  }
334  }
335  groupId = sameGroup ? groupId : -1;
336  }
337  return std::make_tuple(selectedPins, std::make_pair(sameGroup, groupId), onlyPins);
338  }
339 
340 } // 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 * 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
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:983
PinGroup< ModulePin > * get_pin_group_by_id(const u32 id) const
Definition: module.cpp:1034
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)
A model to represent the ports of a module.
Net * getNetFromItem(PortTreeItem *item)
static const int sDirectionColumn
static const int sNameColumn
static const int sTypeColumn
void numberOfPortsChanged(const int newNumber)
Definition: net.h:58
Module * get_module_by_id(u32 module_id) const
Definition: netlist.cpp:613
Type itemType() const
QVariant getData(int column) const override
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)