HAL
module_ports_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  PortTreeItem* clickedItem = static_cast<PortTreeItem*>(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<PortTreeItem*>(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() == PortTreeItem::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("Delete pin group", [itemId, mod]() {
176  auto* pinGroup = mod->get_pin_group_by_id(itemId);
177  if (pinGroup != nullptr)
178  {
180  if (act) act->exec();
181  }
182  });
183 
184  if (selectionModel()->selectedRows().size() > 1)
185  appendMultiSelectionEntries(menu, modId);
186 
187  menu.addSection("Python");
188  menu.addAction(QIcon(":/icons/python"), "Get pin group", [modId, itemId]() { QApplication::clipboard()->setText(PyCodeProvider::pyCodeModulePinGroup(modId, itemId)); });
189  menu.move(mapToGlobal(pos));
190  menu.exec();
191  return;
192  }
193 
194  //menu.addSection("Misc");
195  if (n) //should never be nullptr, but you never know
196  {
197  menu.addAction("Change name", [mod, name, itemId]() {
198  InputDialog ipd("Change pin name", "New pin name", name);
199  if (ipd.exec() == QDialog::Accepted)
200  {
201  if (ipd.textValue().isEmpty())
202  return;
203  auto* pin = mod->get_pin_by_id(itemId);
204  if (pin != nullptr)
205  {
206  ActionPingroup* act = new ActionPingroup(PinActionType::PinRename,pin->get_id(),ipd.textValue());
208  act->exec();
209  }
210  }
211  });
212 
213  menu.addAction("Change type", [mod, name, itemId]() {
214  auto* pin = mod->get_pin_by_id(itemId);
215  if (pin == nullptr)
216  return;
217 
218  QStringList types;
219  for (auto const& [k, v] : EnumStrings<PinType>::data)
220  types << QString::fromStdString(v);
221 
222  ComboboxDialog cbd("Pin Types", "Select pin type", types);
223 
224  if (cbd.exec() == QDialog::Accepted)
225  {
226  PinType ptype = enum_from_string<PinType>(cbd.textValue().toStdString(),PinType::none);
227 
228  ActionPingroup* act = new ActionPingroup(PinActionType::PinTypeChange,pin->get_id(),"",(int)ptype);
230  act->exec();
231  }
232  });
233  menu.addAction("Add net to current selection", [this, n]() {
234  gSelectionRelay->addNet(n->get_id());
236  });
237  menu.addAction("Set net as current selection", [this, n]() {
239  gSelectionRelay->addNet(n->get_id());
241  });
242  }
243  //can be both single(simple right-click, no real selection) and multi-selection
244  if (sameGroup.first && mod->get_pin_group_by_id(sameGroup.second)->size() > 1)
245  {
246  menu.addAction("Remove selection from group", [selectedPins, mod /*, sameGroup*/]() {
248  for (auto item : selectedPins)
249  pins.append(static_cast<PortTreeItem*>(item)->id());
250 
252  if (act) act->exec();
253  });
254  }
255 
256  //multi-selection (part of misc)
257  if (selectionModel()->selectedRows().size() > 1)
258  appendMultiSelectionEntries(menu, modId);
259 
260  menu.addSection("Python");
261  if(clickedItem->itemType()==PortTreeItem::Pin)
262  menu.addAction(QIcon(":/icons/python"), "Get pin", [modId, itemId]() { QApplication::clipboard()->setText(PyCodeProvider::pyCodeModulePinById(modId, itemId)); });
263  else
264  menu.addAction(QIcon(":/icons/python"), "Get group", [modId, itemId]() { QApplication::clipboard()->setText(PyCodeProvider::pyCodeModulePinGroup(modId, itemId)); });
265 
266  menu.move(mapToGlobal(pos));
267  menu.exec();
268  }
269 
270  void ModulePinsTree::handleNumberOfPortsChanged(int newNumberPorts)
271  {
272  Q_EMIT updateText(QString("Pins (%1)").arg(newNumberPorts));
273  }
274 
275  void ModulePinsTree::appendMultiSelectionEntries(QMenu& menu, int modId)
276  {
277  QList<BaseTreeItem*> selectedPins;
278  std::pair<bool, int> sameGroup;
279  bool onlyPins;
280  std::tie(selectedPins, sameGroup, onlyPins) = getSelectedPins();
281  if (selectedPins.size() > 1)
282  {
283  menu.addAction("Add objects to new pin group", [selectedPins, modId]() {
284  InputDialog ipd("Pingroup name", "New pingroup name", "ExampleName");
285  if (ipd.exec() == QDialog::Accepted && !ipd.textValue().isEmpty())
286  {
288  Module* mod = gNetlist->get_module_by_id(modId);
289  for (auto item : selectedPins)
290  {
291  auto* pin = mod->get_pin_by_id(static_cast<PortTreeItem*>(item)->id());
292  if (pin == nullptr)
293  return;
294  pins.append(pin->get_id());
295  }
296 
297  ActionPingroup* act = ActionPingroup::addPinsToNewGroup(mod,ipd.textValue(),pins);
298  if (act) act->exec();
299  }
300  });
301  }
302  }
303 
304  std::tuple<QList<BaseTreeItem*>, std::pair<bool, int>, bool> ModulePinsTree::getSelectedPins()
305  {
306  QList<BaseTreeItem*> selectedPins; //ordered
307  QSet<BaseTreeItem*> alreadyProcessedPins; //only for performance purposes
308  bool sameGroup = true;
309  bool onlyPins = true;
310  int groupId = -1;
311  for (auto index : selectionModel()->selectedRows())
312  {
313  PortTreeItem* item = static_cast<PortTreeItem*>(mPortModel->getItemFromIndex(index));
314  if (item->itemType() == PortTreeItem::Pin)
315  {
316  if (!alreadyProcessedPins.contains(item))
317  {
318  selectedPins.append(item);
319  alreadyProcessedPins.insert(item);
320  }
321  }
322  else if (item->itemType() == PortTreeItem::Group)
323  {
324  onlyPins = false;
325  for (auto pinItem : item->getChildren())
326  {
327  if (!alreadyProcessedPins.contains(pinItem))
328  {
329  selectedPins.append(pinItem);
330  alreadyProcessedPins.insert(pinItem);
331  }
332  }
333  }
334  }
335  //Check if all pins are from the same group (if no pin is selected it is from the same group)
336  if (!selectedPins.isEmpty())
337  {
338  auto mod = gNetlist->get_module_by_id(mModuleID);
339  auto* firstPin = mod->get_pin_by_id(static_cast<PortTreeItem*>(selectedPins.front())->id());
340  groupId = firstPin->get_group().first->get_id();
341  for (auto pinTreeItem : selectedPins)
342  {
343  auto pin = mod->get_pin_by_id(static_cast<PortTreeItem*>(pinTreeItem)->id());
344  if (groupId != (int)pin->get_group().first->get_id())
345  {
346  sameGroup = false;
347  break;
348  }
349  }
350  groupId = sameGroup ? groupId : -1;
351  }
352  return std::make_tuple(selectedPins, std::make_pair(sameGroup, groupId), onlyPins);
353  }
354 
355 } // 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 * 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)
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)