HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
wave_tree_model.cpp
Go to the documentation of this file.
10 #include "rapidjson/document.h"
11 #include "rapidjson/reader.h"
12 #include "rapidjson/filereadstream.h"
13 #include <QApplication>
14 #include <QFont>
15 #include <QMimeData>
16 #include <QAction>
17 #include <stdlib.h>
18 
19 namespace hal {
20 
22  : QAbstractItemModel(obj), mWaveDataList(wdlist), mWaveItemHash(wHash), mGraphicsCanvas(wgc),
23  mDragCommand(None), mDragIsGroup(false),
24  mCursorTime(0), mCursorXpos(0),
25  mReorderRequestWaiting(0), mNumberEntriesChangedEvents(0)
26  {
27 
28  mRoot = new WaveDataRoot(mWaveDataList);
30 
31  /*
32  for (int i=100; i<104; i++)
33  mRoot->append(new WaveTreeItem( i, QString("item%1").arg(i) ));
34 
35  for (int i=0; i<3; i++)
36  {
37  WaveTreeGroup* wtg = new WaveTreeGroup(i+1, QString("group%1").arg(i+1));
38  for (int j=0; j<4; j++)
39  wtg->append(new WaveTreeItem( (i+1)*10+j, QString("gitem%1").arg((i+1)*10+j) ));
40  mRoot->append(wtg);
41  }
42  for (int i=104; i<108; i++)
43  mRoot->append(new WaveTreeItem( i, QString("item%1").arg(i) ));
44  */
45  }
46 
48  {
49  if (!index.isValid()) return nullptr;
50  WaveDataGroup* grp = static_cast<WaveDataGroup*>(index.internalPointer());
51  if (!grp) return mRoot;
52  return grp->childAt(index.row());
53  }
54 
56  {
57  WaveData* wd = item(index);
58  if (!wd) return WaveItemIndex();
59  switch (wd->netType())
60  {
61  case WaveData::NetGroup:
64  return WaveItemIndex(wd->id(),WaveItemIndex::Bool);
66  return WaveItemIndex(wd->id(),WaveItemIndex::Trig);
67  default:
68  break;
69  }
70  int iwave = mWaveDataList->waveIndexByNetId(wd->id());
71  WaveDataGroup* parentGrp = static_cast<WaveDataGroup*>(index.internalPointer());
72  if (!parentGrp || parentGrp == mRoot) return WaveItemIndex(iwave,WaveItemIndex::Wire);
73  return WaveItemIndex(iwave,WaveItemIndex::Wire,parentGrp->id());
74  }
75 
76  QModelIndex WaveTreeModel::index(int row, int column, const QModelIndex &parent) const
77  {
78  WaveData* wd = item(parent);
79  if (!wd) return createIndex(row,0,mRoot);
80  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(wd);
81  if (!grp || row >= grp->size()) return QModelIndex();
82  return createIndex(row,column,grp);
83  }
84 
86  {
89  JsonWriteObject& jwfv = jwd.add_object("waveform_viewer");
90  JsonWriteArray& jitems = jwfv.add_array("items");
91  for (WaveData* wd : mRoot->children())
92  {
93  JsonWriteObject& jitem = jitems.add_object();
94  jitem["id"] = (int) wd->id();
95  jitem["name"] = wd->name().toStdString();
96  jitem["type"] = (int) wd->composedType();
97  jitem.close();
98  }
99  jitems.close();
100 
101  if (!mGraphicsCanvas->renderEngine()->zoomHistory().isEmpty())
102  {
103  JsonWriteArray& jzooms = jwfv.add_array("zoom_history");
104  for (const WaveZoomShift& wzs : mGraphicsCanvas->renderEngine()->zoomHistory())
105  {
106  JsonWriteObject& jzoom = jzooms.add_object();
107  jzoom["scale"] = (double) wzs.scale();
108  jzoom["tleft"] = (uint64_t) wzs.leftTime();
109  jzoom["width"] = (int) wzs.width();
110  jzoom.close();
111  }
112  jzooms.close();
113  }
114  jwfv.close();
115  return jwd.serialize(workDir.absoluteFilePath("waveform_viewer.json").toStdString());
116  }
117 
119  {
120  QDir workDir(QFileInfo(QString::fromStdString(mWaveDataList->saleaeDirectory().get_directory())).path());
121  FILE* ff = fopen(workDir.absoluteFilePath("waveform_viewer.json").toUtf8().data(), "rb");
122  if (!ff) return;
123 
124  char buffer[65536];
125  rapidjson::FileReadStream frs(ff, buffer, sizeof(buffer));
126  rapidjson::Document document;
127  document.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(frs);
128  fclose(ff);
129 
130  if (document.HasParseError() || !document.HasMember("waveform_viewer")) return;
131  auto jwfv = document["waveform_viewer"].GetObject();
132  ReorderRequest req(this);
133 
134  mRoot->clearAll();
135  for (auto it = mWaveItemHash->begin(); it != mWaveItemHash->end(); ++it)
136  delete it.value();
137  mWaveItemHash->clear();
138 
139  if (jwfv.HasMember("items"))
140  {
141  for (auto& jitem : jwfv["items"].GetArray())
142  {
143 
144  u32 id = jitem.HasMember("id") ? jitem["id"].GetUint() : 0;
145  if (!id) continue;
146  std::string name = jitem.HasMember("name") ? jitem["name"].GetString() : std::string();
147  int composedType = jitem.HasMember("type") ? jitem["type"].GetInt() : 0;
148 
149  switch (composedType)
150  {
152  {
153  WaveDataGroup* wdGrp = mWaveDataList->mDataGroups.value(id);
154  if (wdGrp)
155  {
156  handleGroupAdded(id);
157  for (WaveData* wd : wdGrp->children())
158  {
159  int iwave = mWaveDataList->waveIndexByNetId(wd->id());
160  WaveItemIndex wii(iwave, WaveItemIndex::Wire, wdGrp->id());
161  if (!mWaveItemHash->contains(wii)) // unless already in model
162  {
163  addOrReplaceItem(wd, WaveItemIndex::Wire, iwave, wdGrp->id());
164  }
165  }
166  }
167  break;
168  }
170  {
171  WaveDataBoolean* wdBool = mWaveDataList->mDataBooleans.value(id);
172  if (wdBool)
173  {
174  handleBooleanAdded(id);
175  }
176  break;
177  }
179  {
180  WaveDataTrigger* wdTrig = mWaveDataList->mDataTrigger.value(id);
181  if (wdTrig)
182  {
183  handleTriggerAdded(id);
184  }
185  break;
186  }
187  default:
188  {
189  int iwave = mWaveDataList->waveIndexByNetId(id);
190  if (iwave >= 0)
191  {
192  handleWaveAdded(iwave);
193  }
194  }
195  }
196  }
197  }
198  if (jwfv.HasMember("zoom_history"))
199  {
201  for (auto& jzoom : jwfv["zoom_history"].GetArray())
202  {
203  float sc = jzoom.HasMember("scale") ? jzoom["scale"].GetDouble() : 1.;
204  float tl = jzoom.HasMember("tleft") ? jzoom["tleft"].GetUint64() : 0;
205  float wd = jzoom.HasMember("width") ? jzoom["width"].GetInt() : 640;
206  zh.append(WaveZoomShift(sc,tl,wd));
207  }
208  mGraphicsCanvas->renderEngine()->setZoomHistory(zh);
209  mGraphicsCanvas->undoZoom();
210  }
211  mWaveDataList->emitTimeframeChanged();
212  emitReorder();
213  }
214 
215  QModelIndexList WaveTreeModel::indexes(const WaveData* wd) const
216  {
217  QModelIndexList retval;
218  int rootRow = 0;
219  for (WaveData* rootChild : mRoot->children())
220  {
221  if (rootChild == wd)
222  retval.append(createIndex(rootRow,0,mRoot));
223  else
224  {
225  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(rootChild);
226  if (grp)
227  {
228  int groupRow = 0;
229  for (const WaveData* grpChild : grp->children())
230  {
231  if (grpChild == wd)
232  retval.append(createIndex(groupRow,0,grp));
233  groupRow++;
234  }
235  }
236  }
237  rootRow++;
238  }
239  return retval;
240  }
241 
242  QModelIndexList WaveTreeModel::indexes(const QSet<u32>& netIds) const
243  {
244  QModelIndexList retval;
245  int rootRow = 0;
246  for (WaveData* rootChild : mRoot->children())
247  {
248  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(rootChild);
249  if (grp)
250  {
251  int groupRow = 0;
252  for (const WaveData* grpChild : grp->children())
253  {
254  if (netIds.contains(grpChild->id()))
255  for (int icol=0; icol<3; icol++)
256  retval.append(createIndex(groupRow,0,grp));
257  groupRow++;
258  }
259  }
260  else
261  {
262  if (netIds.contains(rootChild->id()))
263  for (int icol=0; icol<3; icol++)
264  retval.append(createIndex(rootRow,0,mRoot));
265  }
266  rootRow++;
267  }
268  return retval;
269  }
270 
271  void WaveTreeModel::emitReorder()
272  {
274  }
275 
277  {
278  ReorderRequest req(this);
279  WaveItemIndex wii(trigId, WaveItemIndex::Trig);
280  if (mWaveItemHash->contains(wii)) return;
281  WaveDataTrigger* wdTrig = mWaveDataList->mDataTrigger.value(trigId);
282  if (!wdTrig) return;
283  insertTrigger(createIndex(mRoot->size(),0,mRoot),QList<WaveData*>(),QList<int>(),nullptr,wdTrig);
284  addOrReplaceItem(wdTrig, WaveItemIndex::Trig, wdTrig->id(), 0);
285  }
286 
288  {
289  ReorderRequest req(this);
290  WaveItemIndex wii(boolId, WaveItemIndex::Bool);
291  if (mWaveItemHash->contains(wii)) return;
292  WaveDataBoolean* wdBool = mWaveDataList->mDataBooleans.value(boolId);
293  if (!wdBool) return;
294  insertBoolean(createIndex(mRoot->size(),0,mRoot),QString(),wdBool);
295  addOrReplaceItem(wdBool, WaveItemIndex::Bool, wdBool->id(), 0);
296  }
297 
299  {
300  ReorderRequest req(this);
302  if (mWaveItemHash->contains(wii)) return;
303  WaveDataGroup* grp = mWaveDataList->mDataGroups.value(grpId);
304  if (!grp) return;
305  insertGroup(createIndex(mRoot->size(),0,mRoot),grp);
306  addOrReplaceItem(grp, WaveItemIndex::Group, grp->id(), 0);
307  }
308 
309  void WaveTreeModel::addOrReplaceItem(WaveData* wd, WaveItemIndex::IndexType tp, int iwave, int parentId)
310  {
311  int oldCount = mWaveItemHash->size();
312  WaveItem* wi = mWaveItemHash->addOrReplace(wd,tp,iwave,parentId);
314  int count = mWaveItemHash->size();
315  if (count != oldCount)
316  {
317  ++mNumberEntriesChangedEvents;
319  }
320  }
321 
323  {
324  if (mNumberEntriesChangedEvents <= 0) return 0;
325  return --mNumberEntriesChangedEvents;
326  }
327 
329  {
330  WaveItemIndex wii(iwave, WaveItemIndex::Wire, 0);
331  if (mWaveItemHash->contains(wii)) return; // already in model
332  ReorderRequest req(this);
333  WaveData* wd = mWaveDataList->at(iwave);
334  insertItem(mRoot->size(),createIndex(0,0,nullptr),wd);
335  addOrReplaceItem(wd, WaveItemIndex::Wire, iwave, 0);
336  }
337 
339  {
340  ReorderRequest req(this);
341 
342  beginResetModel();
343  mRoot->addWaves(wds);
344  for (WaveData* wd : wds)
345  {
346  int iwave = mWaveDataList->waveIndexByNetId(wd->id());
347  addOrReplaceItem(wd, WaveItemIndex::Wire, iwave, 0);
348  }
349  endResetModel();
350 
351  invalidateParent(createIndex(0,0,nullptr)); // update root
352  }
353 
355  {
356  WaveData* wd = mWaveDataList->at(iwave);
357  for (QModelIndex inx : indexes(wd))
358  Q_EMIT dataChanged(inx,inx);
359  }
360 
362  {
363  WaveDataGroup* grp = mWaveDataList->mDataGroups.value(grpId);
364  if (grp)
365  {
366  int irow = mRoot->childIndex(grp);
367  if (irow >= 0)
368  {
369  QModelIndex inx = createIndex(irow,0,mRoot);
370  Q_EMIT dataChanged(inx,inx);
371  }
372  }
373  }
374 
376  {
377  WaveDataGroup* grp = mWaveDataList->mDataGroups.value(grpId);
378  if (!grp) return;
379 
380  ReorderRequest req(this);
381  for (u32 netId : netIds)
382  {
383  int iwave = mWaveDataList->waveIndexByNetId(netId);
384  WaveData* wd = mWaveDataList->at(iwave);
385 
386  WaveItemIndex wii(iwave, WaveItemIndex::Wire, grpId);
387  WaveItem* wi = nullptr;
388 
389  if (grpId)
390  {
391  // check whether waveform graph to be added to group is already present in root
392  int iRootInx = mRoot->netIndex(netId);
393  if (iRootInx >= 0)
394  wi = removeItemFromHash(iRootInx,createIndex(0,0,nullptr));
395  }
396 
397  if (wi)
398  {
400  mWaveItemHash->insert(wii,wi);
401  }
402  else
403  {
404  wi = mWaveItemHash->value(wii);
405  if (!wi)
406  addOrReplaceItem(wd,WaveItemIndex::Wire,iwave,grpId);
407  else
408  {
409  if (wi->wavedata() != wd)
410  wi->setWaveData(wd);
414  }
415  }
416 
417  if (mDragCommand == Move)
418  {
419  for (QModelIndex inx : indexes(wd))
420  {
421  if (inx.internalPointer() == grp) continue;
422  if (inx.internalPointer() == mRoot) continue;
423  mWaveItemHash->dispose(removeItemFromHash(inx.row(),inx.parent()));
424  }
425  }
426  }
427  mDragCommand = None;
428  }
429 
430  QVariant WaveTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
431  {
432  if (orientation != Qt::Horizontal) return QVariant();
433  if (role == Qt::SizeHintRole)
434  return QSize(400,28);
435  if (role != Qt::DisplayRole) return QVariant();
436  switch (section)
437  {
438  case 0: return "Name";
439  case 1: return "ID";
440  case 2: return "Value";
441  }
442  return QVariant();
443  }
444 
446  {
447  switch (role)
448  {
449  case Qt::FontRole:
450  {
451  QFont font = qApp->font();
452  if (!isLeaveItem(index) || index.column() == 2)
453  {
454  font.setPixelSize(14);
455  font.setBold(true);
456  }
457  return font;
458  }
459  case Qt::SizeHintRole:
460  return QSize(400,28);
462  if (!index.column())
463  return Qt::AlignLeft;
464  return Qt::AlignRight;
465  case Qt::ForegroundRole:
466  if (index.column() != 2) return QVariant();
467  return QColor(Qt::white);
468  case Qt::BackgroundRole:
469  {
470  if (index.column() != 2) return QVariant();
471  int v = valueAtCursor(index);
473  return QColor::fromRgb(255,255,qrand()%256);
474  if (v<-1) v=-1;
475  if (v>1) v=1;
477  }
478  case Qt::DisplayRole:
479  {
480  WaveData* wd = item(index);
481  if (!wd) return QVariant();
482  switch (index.column())
483  {
484  case 0:
485  return wd->name();
486  case 1:
487  if (wd->id() < 1)
488  return QString();
489  return QString::number(wd->id());
490  case 2:
491  int v = valueAtCursor(index);
493  return QString();
494  return wd->strValue(v);
495  }
496  }
497  default:
498  break;
499  }
500 
501  return QVariant();
502  }
503 
505  {
506  WaveData* wd = item(index);
507  if (!wd) return -99;
508  if (dynamic_cast<WaveDataGroup*>(wd)) return -1;
509  if (dynamic_cast<WaveDataBoolean*>(wd)) return -2;
510  if (dynamic_cast<WaveDataTrigger*>(wd)) return -3;
511  return mWaveDataList->waveIndexByNetId(wd->id());
512  }
513 
514  int WaveTreeModel::triggerId(const QModelIndex& trigIndex) const
515  {
516  WaveDataTrigger* wdTrig = dynamic_cast<WaveDataTrigger*>(item(trigIndex));
517  if (!wdTrig) return -1;
518  return wdTrig->id();
519  }
520 
521  int WaveTreeModel::booleanId(const QModelIndex& boolIndex) const
522  {
523  WaveDataBoolean* wdBool = dynamic_cast<WaveDataBoolean*>(item(boolIndex));
524  if (!wdBool) return -1;
525  return wdBool->id();
526  }
527 
528  int WaveTreeModel::groupId(const QModelIndex& grpIndex) const
529  {
530  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(item(grpIndex));
531  if (!grp) return -1;
532  return grp->id();
533  }
534 
536  {
537  WaveData* wd = item(index);
538  if (!wd) return QString();
539  return wd->name();
540  }
541 
542  int WaveTreeModel::rowCount(const QModelIndex &parent) const
543  {
544  if (!parent.isValid())
545  return mRoot->size();
546  WaveData* wd = item(parent);
547  if (!wd) return 0;
548  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(wd);
549  if (!grp) return 0;
550  return grp->size();
551  }
552 
553  int WaveTreeModel::columnCount(const QModelIndex &parent) const
554  {
555  Q_UNUSED(parent);
556  return 3;
557  }
558 
560  {
561  if (!child.isValid()) return QModelIndex();
562  WaveDataGroup* grp = static_cast<WaveDataGroup*>(child.internalPointer());
563  if (!grp) return QModelIndex();
564  if (grp == mRoot)
565  return createIndex(0,0,nullptr);
566 
567  int n = mRoot->size();
568  for (int i=0; i<n; i++)
569  {
570  if (mRoot->childAt(i) == grp)
571  {
572  return createIndex(i,0,mRoot);
573  }
574  }
575  return QModelIndex();
576  }
577 
579  {
580  beginResetModel();
581  }
582 
584  {
585  endResetModel();
586  }
587 
589  {
591  }
592 
594  {
596  if (!index.isValid()) return retval;
597  retval |= Qt::ItemIsDragEnabled;
598  if (isLeaveItem(index)) return retval | Qt::ItemNeverHasChildren;
599  return retval;
600  }
601 
602  void WaveTreeModel::setDragIndexes(const QModelIndexList& indexList) {
603  mDragIsGroup = true;
604  mDragIndexList.clear();
605 
606 
607  for (const QModelIndex& inx : indexList)
608  {
609  if (isLeaveItem(inx))
610  {
611  mDragIsGroup = false;
612  break;
613  }
614  }
615 
616  if (mDragIsGroup)
617  {
618  mDragIndexList = indexList;
619  }
620  else
621  {
622  mDragIndexList.clear();
623  for (const QModelIndex& inx : indexList)
624  if (isLeaveItem(inx))
625  mDragIndexList.append(inx);
626  }
627  mDragCommand = Move;
628  }
629 
630  bool WaveTreeModel::dropGroup(const QModelIndex &parentTo, int row)
631  {
632  ReorderRequest req(this);
633  if (row < 0) row = parentTo.row();
634  bool couldDrop = false;
635  beginResetModel();
636  for (const QModelIndex& inx : mDragIndexList)
637  {
638  if (inx.column()) continue;
639  if (inx.internalPointer() != mRoot) continue;
640  if (!mRoot->moveGroupPosition(inx.row(),row)) continue;
641  couldDrop = true;
642  }
643  endResetModel();
644  return couldDrop;
645  }
646 
647  void WaveTreeModel::dropRow(const QModelIndex& parentTo, int row)
648  {
649  ReorderRequest req(this);
650  int targetRow = row;
651 
652  WaveDataGroup* targetGrp = static_cast<WaveDataGroup*>(isLeaveItem(parentTo)
653  ? parentTo.internalPointer()
654  : item(parentTo));
655 
656  QList<WaveItem*> wiTempList;
657 
658  for (QModelIndex inxSource : mDragIndexList)
659  {
660  if (inxSource.column()) continue;
661  QModelIndex sourceParentIndex = inxSource.parent();
662  WaveDataGroup* sourceGrp = static_cast<WaveDataGroup*>(inxSource.internalPointer());
663  if (targetRow > 0 && sourceGrp == targetGrp && inxSource.row() < targetRow)
664  --targetRow; // compensate position for removed items
665  WaveItem* wi = removeItemFromHash(inxSource.row(),sourceParentIndex);
666  if (!wi) continue;
667  wiTempList.append(wi);
668  }
669 
670  QModelIndex targetIndex = createIndex(targetRow,0,targetGrp);
671  QModelIndex targetIndexParent = targetIndex.parent();
672 
673  for (WaveItem* wi : wiTempList)
674  insertExisting(targetRow,targetIndexParent,wi);
675  Q_EMIT inserted(index(targetRow,0,targetIndexParent));
676  }
677 
678  void WaveTreeModel::handleCursorMoved(u64 tCursor, int xpos)
679  {
680  if (tCursor == mCursorTime && xpos == mCursorXpos) return;
681  if (!mValueThreads.isEmpty())
682  {
683  for (WaveValueThread* wvt : mValueThreads.values())
684  wvt->abort();
685  }
686  mCursorTime = tCursor;
687  mCursorXpos = xpos;
689  }
690 
692  {
693  bool workDone = false;
694  auto it = mValueThreads.find(item);
695  if (it != mValueThreads.end())
696  {
697  workDone = !it.value()->wasAborted();
698  mValueThreads.erase(it);
699  }
700  if (workDone)
702  }
703 
705  {
706  QModelIndex i0 = createIndex(0,2,mRoot);
707  QModelIndex i1 = createIndex(mRoot->size()-1,2,mRoot);
708 
709  Q_EMIT dataChanged(i0,i1);
710  for (WaveDataGroup* grp : mWaveDataList->mDataGroups.values())
711  {
712  int n = grp->size();
713  if (!n) continue;
714  i0 = createIndex(0,2,grp);
715  i1 = createIndex(n-1,2,grp);
716  Q_EMIT dataChanged(i0,i1);
717  }
718  }
719 
720  bool WaveTreeModel::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &dropParent)
721  {
722  Q_UNUSED(action);
723  Q_UNUSED(column);
724  if (!dropParent.isValid()) return false;
725  if (!mimeData->formats().contains("application/x-qabstractitemmodeldatalist")) return false;
726  if (mDragIsGroup) return dropGroup(dropParent,row);
727 
728  // drop on wave item, insert behind
729  if (isLeaveItem(dropParent))
730  {
731  WaveData* wd = item(dropParent);
732  WaveDataGroup* grp = static_cast<WaveDataGroup*>(dropParent.internalPointer());
733  int n=grp->size();
734  for (int i=0; i<n; i++)
735  if (grp->childAt(i) == wd)
736  {
737  dropRow(dropParent.parent(),i+1);
738  return true;
739  }
740  return false;
741  }
742 
743  // drop on group item
744  if (dropParent.internalPointer() == mRoot)
745  {
746  dropRow(dropParent,row >= 0 ? row : 0);
747  return true;
748  }
749  return false;
750  }
751 
752  bool WaveTreeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
753  {
754  Q_UNUSED(action);
755  Q_UNUSED(row);
756  Q_UNUSED(column);
757  if (!parent.isValid()) return false;
758  if (!data->formats().contains("application/x-qabstractitemmodeldatalist")) return false;
759  if (parent.internalPointer() == mRoot) return true;
760  if (!mDragIsGroup && isLeaveItem(parent)) return true;
761  return false;
762  }
763 
765  {
766  WaveData* wd = item(index);
767  if (!wd) return false;
768  return dynamic_cast<WaveDataGroup*>(wd)==nullptr;
769  }
770 
771  //TODO : unify insertExisting und insertItem
772  void WaveTreeModel::insertExisting(int row, const QModelIndex& parent, WaveItem* wi)
773  {
774  if (!parent.isValid()) return;
775  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(item(parent));
776  if (!grp) return;
777  if (row < 0) row = 0;
778  if (row > grp->size()) row = grp->size();
779 
780  const WaveData* wdConst = wi->wavedata();
781  WaveData* wd = nullptr;
782  int iwave = -1;
784  int grpId = grp->id();
785 
786  switch (wdConst->netType())
787  {
788  case WaveData::NetGroup:
789  inxTp = WaveItemIndex::Group;
790  iwave = wdConst->id();
791  grpId = 0;
792  wd = mWaveDataList->mDataGroups.value(iwave);
793  break;
795  inxTp = WaveItemIndex::Bool;
796  iwave = wdConst->id();
797  grpId = 0;
798  wd = mWaveDataList->mDataBooleans.value(iwave);
799  break;
801  inxTp = WaveItemIndex::Trig;
802  iwave = wdConst->id();
803  grpId = 0;
804  wd = mWaveDataList->mDataTrigger.value(iwave);
805  break;
806  default:
807  inxTp = WaveItemIndex::Wire;
808  iwave = mWaveDataList->waveIndexByNetId(wi->wavedata()->id());
809  wd = mWaveDataList->at(iwave);
810  break;
811  }
812  if (iwave < 0 || !wd) return;
813 
814  beginResetModel();
815  grp->insert(row,wd);
816  grp->recalcData();
817  endResetModel();
818 
819  WaveItemIndex wii(iwave, inxTp, grpId);
820  mWaveItemHash->insert(wii,wi);
821  invalidateParent(parent);
822  }
823 
824  bool WaveTreeModel::insertItem(int row, const QModelIndex &parent, WaveData *wd)
825  {
826  if (!parent.isValid()) return false;
827  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(item(parent));
828  if (!grp) return false;
829  if (row < 0) row = 0;
830  if (row > grp->size()) row = grp->size();
831 
832  beginResetModel();
833  grp->insert(row,wd);
834  grp->recalcData();
835  endResetModel();
836 
837  switch (wd->netType())
838  {
839  case WaveData::NetGroup:
840  {
841  WaveDataGroup* wdGrp = static_cast<WaveDataGroup*>(wd);
842  addOrReplaceItem(wd, WaveItemIndex::Group, wdGrp->id(), 0);
843  break;
844  }
846  {
847  WaveDataBoolean* wdBool = static_cast<WaveDataBoolean*>(wd);
848  wdBool->recalcData();
849  addOrReplaceItem(wd, WaveItemIndex::Bool, wdBool->id(),0);
850  break;
851  }
853  {
854  WaveDataTrigger* wdTrig = static_cast<WaveDataTrigger*>(wd);
855  wdTrig->recalcData();
856  addOrReplaceItem(wd, WaveItemIndex::Trig, wdTrig->id(),0);
857  break;
858  }
859  default:
860  handleWaveAddedToGroup({wd->id()},grp->id());
861  break;
862  }
863 
864  invalidateParent(parent);
865  return true;
866  }
867 
868  void WaveTreeModel::invalidateParent(const QModelIndex &parentRow)
869  {
870  QModelIndex parentValueInx = createIndex(parentRow.row(),2,parentRow.internalPointer());
871  Q_EMIT dataChanged(parentValueInx,parentValueInx);
872  }
873 
875  {
876  if (!mValueThreads.contains(item) && !item->isLoading() && !item->isThreadBusy())
877  {
878  QString workdir = QString::fromStdString(mWaveDataList->saleaeDirectory().get_directory());
879  WaveValueThread* wvt = new WaveValueThread(item,workdir,mCursorTime,mCursorXpos);
881  wvt->start();
882  mValueThreads.insert(item,wvt);
883  }
884  }
885 
886  int WaveTreeModel::valueAtCursor(const QModelIndex& index) const
887  {
888  WaveData* wd = item(index);
889  WaveItemIndex wii;
890  switch (wd->netType())
891  {
892  case WaveData::NetGroup:
893  wii = WaveItemIndex(wd->id(), WaveItemIndex::Group);
894  break;
896  wii = WaveItemIndex(wd->id(), WaveItemIndex::Bool);
897  break;
899  wii = WaveItemIndex(wd->id(), WaveItemIndex::Trig);
900  break;
901  default:
902  WaveDataGroup* grp = static_cast<WaveDataGroup*>(index.internalPointer());
903  int iwave = mWaveDataList->waveIndexByNetId(wd->id());
904  wii = WaveItemIndex(iwave, WaveItemIndex::Wire, grp->id());
905  break;
906  }
907 
908  WaveItem* wi = mWaveItemHash->value(wii);
909  if (!wi) return SaleaeDataTuple::sReadError;
910  int retval = wi->cursorValue(mCursorTime,mCursorXpos);
911  if (retval == SaleaeDataTuple::sReadError)
912  {
914  }
915  return retval;
916  }
917 
918 
920  {
921  if (!parent.isValid()) return nullptr;
922  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(item(parent));
923  if (!grp) return nullptr;
924 
925  ReorderRequest req(this);
926  beginRemoveRows(parent,row,row);
927  WaveData* wd = grp->removeAt(row);
929  endRemoveRows();
930  invalidateParent(parent);
931  grp->recalcData();
932  int iwave = mWaveDataList->waveIndexByNetId(wd->id());
933  switch (wd->netType())
934  {
936  inxTp = WaveItemIndex::Trig;
937  iwave = wd->id();
938  break;
940  inxTp = WaveItemIndex::Bool;
941  iwave = wd->id();
942  break;
943  default:
944  inxTp = WaveItemIndex::Wire;
945  break;
946  }
947  WaveItemIndex wii(iwave, inxTp, grp->id());
948  auto it = mWaveItemHash->find(wii);
949  WaveItem* retval = nullptr;
950  if (it != mWaveItemHash->end())
951  {
952  retval = it.value();
953  mWaveItemHash->erase(it);
954  }
955  return retval;
956  }
957 
958  void WaveTreeModel::removeGroup(const QModelIndex& groupIndex)
959  {
960  if (groupIndex.internalPointer() != mRoot) return;
961 
962  ReorderRequest req(this);
963  int irow = groupIndex.row();
964  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(mRoot->childAt(irow));
965  mWaveDataList->removeGroup(grp->id());
967  auto it = mWaveItemHash->find(wii);
968  if (it != mWaveItemHash->end())
969  {
970  WaveItem* wi = it.value();
971  mWaveItemHash->erase(it);
972  if (wi) mWaveItemHash->dispose(wi);
973  }
974  }
975 
977  {
978  WaveItem* wi = mWaveItemHash->value(WaveItemIndex(grpId,WaveItemIndex::Group));
979  if (wi) wi->setRequest(WaveItem::DataChanged);
980  }
981 
982  void WaveTreeModel::handleWaveRemovedFromGroup(int iwave, int grpId)
983  {
984  WaveItemIndex wii(iwave, WaveItemIndex::Wire, grpId);
985  auto it = mWaveItemHash->find(wii);
986  if (it != mWaveItemHash->end())
987  {
988  beginResetModel();
989  WaveItem* wi = it.value();
990  mWaveItemHash->erase(it);
991  if (wi) mWaveItemHash->dispose(wi);
992  endResetModel();
993  }
994  }
995 
997  {
998  if (!grp) return;
999  int irow = mRoot->childIndex(grp);
1000  if (irow<0) return;
1001 
1002  ReorderRequest req(this);
1003  beginResetModel();
1004  mRoot->removeAt(irow);
1005  if (!grp->isEmpty())
1006  {
1007  int n = grp->size() - 1;
1008  for (int i=n; i>=0; i--)
1009  {
1010  WaveData* wd = grp->childAt(i);
1011  int iwave = mWaveDataList->waveIndexByNetId(wd->id());
1012  // remove wave items from group
1013  auto it = mWaveItemHash->find(WaveItemIndex(iwave,WaveItemIndex::Wire,grp->id()));
1014  if (it != mWaveItemHash->end())
1015  {
1016  WaveItem* wi = it.value();
1017  mWaveItemHash->erase(it);
1018  if (wi) mWaveItemHash->dispose(wi);
1019  }
1020  }
1021  }
1022  endResetModel();
1023  WaveItem* wi = mWaveItemHash->value(WaveItemIndex(grp->id(),WaveItemIndex::Group));
1024  if (wi) wi->setRequest(WaveItem::DeleteRequest);
1025  }
1026 
1027  void WaveTreeModel::insertTrigger(const QModelIndex& trigIndex, const QList<WaveData*>& trigWaves, const QList<int>& toVal, WaveData *wdFilter, WaveDataTrigger *wdTrig)
1028  {
1029  if (trigIndex.internalPointer() != mRoot) return;
1030 
1031  ReorderRequest req(this);
1032  if (!wdTrig)
1033  {
1034  wdTrig = new WaveDataTrigger(mWaveDataList,trigWaves,toVal);
1035  if (wdFilter) wdTrig->set_filter_wave(wdFilter);
1036  }
1037  beginResetModel();
1038  insertItem(trigIndex.row(),trigIndex.parent(),wdTrig);
1039  endResetModel();
1040  wdTrig->recalcData();
1041  }
1042 
1043  void WaveTreeModel::insertBoolean(const QModelIndex& boolIndex, const QString &boolExpression, WaveDataBoolean *wdBool)
1044  {
1045  if (boolIndex.internalPointer() != mRoot) return;
1046 
1047  ReorderRequest req(this);
1048  if (!wdBool) wdBool = new WaveDataBoolean(mWaveDataList,boolExpression);
1049  beginResetModel();
1050  insertItem(boolIndex.row(),boolIndex.parent(),wdBool);
1051  endResetModel();
1052  wdBool->recalcData();
1053  }
1054 
1055  void WaveTreeModel::insertBoolean(const QModelIndex& boolIndex, const QList<WaveData *> &boolWaves, const QList<int>& acceptMask)
1056  {
1057  if (boolIndex.internalPointer() != mRoot) return;
1058 
1059  ReorderRequest req(this);
1060  WaveDataBoolean* wdBool = new WaveDataBoolean(mWaveDataList,boolWaves,acceptMask);
1061  beginResetModel();
1062  insertItem(boolIndex.row(),boolIndex.parent(),wdBool);
1063  endResetModel();
1064  wdBool->recalcData();
1065  }
1066 
1068  {
1069  if (groupIndex.internalPointer() != mRoot) return;
1070 
1071  ReorderRequest req(this);
1072  if (!grp) grp = new WaveDataGroup(mWaveDataList);
1073  beginResetModel();
1074  insertItem(groupIndex.row(),groupIndex.parent(),grp);
1075  endResetModel();
1076  grp->recalcData();
1077  }
1078 
1080  {
1081  QSet<int> retval;
1082  for (const WaveData* wd : mRoot->children())
1083  {
1084  const WaveDataGroup* grp = dynamic_cast<const WaveDataGroup*>(wd);
1085  if (grp)
1086  {
1087  for (const WaveData* wdGrp : grp->children())
1088  {
1089  int iwave = mWaveDataList->waveIndexByNetId(wdGrp->id());
1090  if (iwave >= 0) retval.insert(iwave);
1091  }
1092  }
1093  else
1094  {
1095  int iwave = mWaveDataList->waveIndexByNetId(wd->id());
1096  if (iwave >= 0) retval.insert(iwave);
1097  }
1098  }
1099  return retval;
1100  }
1101 
1102  bool WaveTreeModel::onlyRootItemsSelected(const QModelIndexList& selectList) const
1103  {
1104  for (const QModelIndex& inx : selectList)
1105  if (inx.internalPointer() != mRoot)
1106  return false;
1107  return true;
1108  }
1109 
1110  // ---- WaveDataRoot
1111 
1112  bool WaveDataRoot::moveGroupPosition(int sourceRow, int targetRow)
1113  {
1114  if (targetRow==sourceRow) return false;
1115  WaveDataGroup* grp = dynamic_cast<WaveDataGroup*>(mGroupList.at(sourceRow));
1116  if (!grp) return false;
1117  mGroupList.removeAt(sourceRow);
1118  mGroupList.insert( targetRow, grp);
1119  restoreIndex();
1120  return true;
1121  }
1122 
1123  void WaveDataRoot::dump() const
1124  {
1125  QTextStream xout(stderr, QIODevice::WriteOnly);
1126  const char* ctype = ".GBT ";
1127  xout.setFieldWidth(5);
1128  xout << "---\n";
1129  for (WaveData* wd : mGroupList)
1130  {
1131  xout << wd->id() << ctype[wd->composedType()] << " <" << wd->name() << ">\n";
1132  }
1133  }
1134 
1135  //------------------------
1136 
1137  /*
1138  class WaveValueThread : public QThread
1139  {
1140  Q_OBJECT
1141  WaveItem* mItem;
1142  QDir mWorkDir;
1143  float mTposition;
1144  int mValue;
1145  public:
1146  WaveValueThread(WaveItem* parentItem, const QString& workdir, float tpos);
1147  void run() override;
1148  };
1149  */
1150 
1151 
1152  WaveValueThread::WaveValueThread(WaveItem* item, const QString& workdir, u64 tpos, int xpos, QObject *parent)
1153  : QThread(parent), mItem(item), mWorkDir(workdir), mTpos(tpos), mXpos(xpos), mAbort(false)
1154  {
1155  connect(this,&QThread::finished,this,&WaveValueThread::handleValueThreadFinished);
1156  }
1157 
1159  {
1160  int fileIndex = mItem->wavedata()->fileIndex();
1161  SaleaeInputFile sif(mWorkDir.absoluteFilePath(QString("digital_%1.bin").arg(fileIndex)).toStdString());
1162  if (sif.good())
1163  {
1164  int val = sif.get_int_value(mTpos);
1165  if (!mAbort) mItem->mPainted.setCursorValue(mTpos,mXpos,val);
1166  }
1167  }
1168 
1169  void WaveValueThread::handleValueThreadFinished()
1170  {
1171  Q_EMIT valueThreadEnds(mItem);
1172  deleteLater();
1173  }
1174 
1175  //------------------------
1176 
1177 }
JsonWriteObject & add_object()
bool serialize(const std::string &filename)
JsonWriteObject & add_object(const std::string &tag)
JsonWriteArray & add_array(const std::string &tag)
static const int sReadError
Fake data value to indicate all kind of errors.
Definition: saleae_file.h:165
std::string get_directory() const
Get path to SALEAE directory without filename.
@ Boolean
@ Trigger
@ Group
int get_int_value(double t)
Get waveform value for time t.
virtual bool isEmpty() const
Definition: wave_data.h:350
virtual void recalcData()
Definition: wave_data.cpp:1144
virtual WaveData * childAt(int inx) const
Definition: wave_data.cpp:1062
virtual void addWaves(const QVector< WaveData * > &wds)
Definition: wave_data.cpp:1110
virtual QList< WaveData * > children() const
Definition: wave_data.cpp:1047
virtual int size() const
Definition: wave_data.h:339
virtual void insert(int inx, WaveData *wd)
Definition: wave_data.cpp:1100
virtual int childIndex(WaveData *wd) const
Definition: wave_data.cpp:1068
virtual WaveData * removeAt(int inx)
Definition: wave_data.cpp:1090
QList< WaveData * > mGroupList
Definition: wave_data.h:330
virtual int netIndex(u32 id) const
Definition: wave_data.cpp:1073
SaleaeDirectoryNetEntry::Type composedType() const
Definition: wave_data.cpp:132
int fileIndex() const
Definition: wave_data.h:109
NetType netType() const
Definition: wave_data.h:105
QString name() const
Definition: wave_data.h:104
QString strValue(int val) const
Definition: wave_data.cpp:484
u32 id() const
Definition: wave_data.h:103
QMap< u32, WaveDataGroup * > mDataGroups
Definition: wave_data.h:203
QMap< u32, WaveDataBoolean * > mDataBooleans
Definition: wave_data.h:204
int waveIndexByNetId(u32 id) const
Definition: wave_data.h:227
SaleaeDirectory & saleaeDirectory()
Definition: wave_data.h:242
void emitTimeframeChanged()
Definition: wave_data.cpp:1290
void removeGroup(u32 grpId)
Definition: wave_data.cpp:1553
QMap< u32, WaveDataTrigger * > mDataTrigger
Definition: wave_data.h:205
bool moveGroupPosition(int sourceRow, int targetRow)
void set_filter_wave(WaveData *wd)
Definition: wave_data.cpp:805
void setCursorValue(u64 tCursor, int xpos, int val)
WaveRenderEngine * renderEngine()
void dispose(WaveItem *wi)
Definition: wave_item.cpp:320
WaveItem * addOrReplace(WaveData *wd, WaveItemIndex::IndexType tp, int iwave, int parentId)
Definition: wave_item.cpp:305
const WaveData * wavedata() const
Definition: wave_item.h:129
void setWaveData(WaveData *wd)
Definition: wave_item.cpp:40
@ DeleteAcknowledged
Definition: wave_item.h:74
void setRequest(Request rq)
Definition: wave_item.cpp:266
WaveFormPainted mPainted
Definition: wave_item.h:83
void gotCursorValue()
void clearRequest(Request rq)
Definition: wave_item.cpp:272
QList< WaveZoomShift > & zoomHistory()
void setZoomHistory(const QList< WaveZoomShift > &hist)
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override
void addWaves(const QVector< WaveData * > &wds)
Qt::DropActions supportedDragActions() const override
WaveItem * removeItemFromHash(int row, const QModelIndex &parent)
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
void handleWaveAddedToGroup(const QVector< u32 > &netIds, int grpId)
void handleWaveRemovedFromGroup(int iwave, int grpId)
int triggerId(const QModelIndex &trigIndex) const
QModelIndexList indexes(const WaveData *wd) const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void handleWaveAdded(int iwave)
void numberEntriesChanged(int count)
void handleGroupRenamed(int grpId)
void handleEndValueThread(WaveItem *item)
void insertTrigger(const QModelIndex &trigIndex, const QList< WaveData * > &trigWaves, const QList< int > &toVal, WaveData *wdFilter=nullptr, WaveDataTrigger *wdTrig=nullptr)
QString netName(const QModelIndex &index) const
WaveData * item(const QModelIndex &index) const
void inserted(QModelIndex index)
int decreaseNumberEntriesChangedEvents()
void insertExisting(int row, const QModelIndex &parent, WaveItem *wi)
void handleTriggerAdded(int trigId)
Qt::ItemFlags flags(const QModelIndex &index) const override
void setDragIndexes(const QModelIndexList &indexList)
void handleGroupAboutToBeRemoved(WaveDataGroup *grp)
void handleCursorMoved(u64 tCursor, int xpos)
int waveIndex(const QModelIndex &index) const
void triggerStartValueThread(WaveItem *item) const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void removeGroup(const QModelIndex &groupIndex)
void handleWaveRenamed(int iwave)
void handleGroupAdded(int grpId)
WaveTreeModel(WaveDataList *wdlist, WaveItemHash *wHash, WaveGraphicsCanvas *wgc, QObject *obj=nullptr)
bool onlyRootItemsSelected(const QModelIndexList &selectList) const
int groupId(const QModelIndex &grpIndex) const
bool insertItem(int row, const QModelIndex &parent, WaveData *wd)
void handleStartValueThread(WaveItem *item)
int booleanId(const QModelIndex &boolIndex) const
bool isLeaveItem(const QModelIndex &index) const
QSet< int > waveDataIndexSet() const
int columnCount(const QModelIndex &parent=QModelIndex()) const override
void handleGroupUpdated(int grpId)
void insertGroup(const QModelIndex &groupIndex, WaveDataGroup *grp=nullptr)
bool dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &dropParent) override
void insertBoolean(const QModelIndex &boolIndex, const QString &boolExpression, WaveDataBoolean *wdBool=nullptr)
WaveItemIndex hashIndex(const QModelIndex &index) const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void handleBooleanAdded(int boolId)
void valueThreadEnds(hal::WaveItem *item)
WaveValueThread(WaveItem *item, const QString &workdir, u64 tpos, int xpos, QObject *parent=nullptr)
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
Definition: defines.h:45
std::string name
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)
virtual QMimeData * mimeData(const QModelIndexList &indexes) const const
char * data()
QColor fromRgb(QRgb rgb)
QString absoluteFilePath(const QString &fileName) const const
QString path() const const
void setBold(bool enable)
void setPixelSize(int pixelSize)
QHash::iterator begin()
void clear()
bool contains(const Key &key) const const
QHash::iterator end()
QHash::iterator erase(QHash::iterator pos)
QHash::iterator find(const Key &key)
QHash::iterator insert(const Key &key, const T &value)
int size() const const
const T value(const Key &key) const const
void append(const T &value)
const T & at(int i) const const
void insert(int i, const T &value)
void removeAt(int i)
virtual QStringList formats() const const
int column() const const
void * internalPointer() const const
bool isValid() const const
QModelIndex parent() 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)
void deleteLater()
QObject * parent() const const
bool contains(const T &value) const const
QSet::iterator insert(const T &value)
QString fromStdString(const std::string &str)
QString number(int n, int base)
std::string toStdString() const const
QByteArray toUtf8() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
AlignLeft
QueuedConnection
typedef DropActions
SizeHintRole
typedef ItemFlags
Orientation
void setFieldWidth(int width)
void finished()
void start(QThread::Priority priority)