1 #include "SegmentsWidget.h"
2 #include "core/MainWindow.h"
3 #include "common/Helpers.h"
4 #include "ui_ListDockWidget.h"
5 
6 #include <QVBoxLayout>
7 #include <QShortcut>
8 
SegmentsModel(QList<SegmentDescription> * segments,QObject * parent)9 SegmentsModel::SegmentsModel(QList<SegmentDescription> *segments, QObject *parent)
10     : AddressableItemModel<QAbstractListModel>(parent),
11       segments(segments)
12 {
13 }
14 
rowCount(const QModelIndex &) const15 int SegmentsModel::rowCount(const QModelIndex &) const
16 {
17     return segments->count();
18 }
19 
columnCount(const QModelIndex &) const20 int SegmentsModel::columnCount(const QModelIndex &) const
21 {
22     return SegmentsModel::ColumnCount;
23 }
24 
data(const QModelIndex & index,int role) const25 QVariant SegmentsModel::data(const QModelIndex &index, int role) const
26 {
27     // TODO: create unique colors, e. g. use HSV color space and rotate in H for 360/size
28     static const QList<QColor> colors = { QColor("#1ABC9C"),    //TURQUOISE
29                                           QColor("#2ECC71"),    //EMERALD
30                                           QColor("#3498DB"),    //PETER RIVER
31                                           QColor("#9B59B6"),    //AMETHYST
32                                           QColor("#34495E"),    //WET ASPHALT
33                                           QColor("#F1C40F"),    //SUN FLOWER
34                                           QColor("#E67E22"),    //CARROT
35                                           QColor("#E74C3C"),    //ALIZARIN
36                                           QColor("#ECF0F1"),    //CLOUDS
37                                           QColor("#BDC3C7"),    //SILVER
38                                           QColor("#95A5A6")     //COBCRETE
39                                         };
40 
41     if (index.row() >= segments->count())
42         return QVariant();
43 
44     const SegmentDescription &segment = segments->at(index.row());
45 
46     switch (role) {
47     case Qt::DisplayRole:
48         switch (index.column()) {
49         case SegmentsModel::NameColumn:
50             return segment.name;
51         case SegmentsModel::SizeColumn:
52             return QString::number(segment.size);
53         case SegmentsModel::AddressColumn:
54             return RAddressString(segment.vaddr);
55         case SegmentsModel::EndAddressColumn:
56             return RAddressString(segment.vaddr + segment.size);
57         case SegmentsModel::PermColumn:
58             return segment.perm;
59         case SegmentsModel::CommentColumn:
60             return Core()->getCommentAt(segment.vaddr);
61         default:
62             return QVariant();
63         }
64     case Qt::DecorationRole:
65         if (index.column() == 0)
66             return colors[index.row() % colors.size()];
67         return QVariant();
68     case SegmentsModel::SegmentDescriptionRole:
69         return QVariant::fromValue(segment);
70     default:
71         return QVariant();
72     }
73 }
74 
headerData(int segment,Qt::Orientation,int role) const75 QVariant SegmentsModel::headerData(int segment, Qt::Orientation, int role) const
76 {
77     switch (role) {
78     case Qt::DisplayRole:
79         switch (segment) {
80         case SegmentsModel::NameColumn:
81             return tr("Name");
82         case SegmentsModel::SizeColumn:
83             return tr("Size");
84         case SegmentsModel::AddressColumn:
85             return tr("Address");
86         case SegmentsModel::EndAddressColumn:
87             return tr("End Address");
88         case SegmentsModel::PermColumn:
89             return tr("Permissions");
90         case SegmentsModel::CommentColumn:
91             return tr("Comment");
92         default:
93             return QVariant();
94         }
95     default:
96         return QVariant();
97     }
98 }
99 
address(const QModelIndex & index) const100 RVA SegmentsModel::address(const QModelIndex &index) const
101 {
102     const SegmentDescription &segment = segments->at(index.row());
103     return segment.vaddr;
104 }
105 
name(const QModelIndex & index) const106 QString SegmentsModel::name(const QModelIndex &index) const
107 {
108     const SegmentDescription &segment = segments->at(index.row());
109     return segment.name;
110 }
111 
SegmentsProxyModel(SegmentsModel * sourceModel,QObject * parent)112 SegmentsProxyModel::SegmentsProxyModel(SegmentsModel *sourceModel, QObject *parent)
113     : AddressableFilterProxyModel(sourceModel, parent)
114 {
115     setFilterCaseSensitivity(Qt::CaseInsensitive);
116     setSortCaseSensitivity(Qt::CaseInsensitive);
117 }
118 
lessThan(const QModelIndex & left,const QModelIndex & right) const119 bool SegmentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
120 {
121     auto leftSegment = left.data(SegmentsModel::SegmentDescriptionRole).value<SegmentDescription>();
122     auto rightSegment = right.data(SegmentsModel::SegmentDescriptionRole).value<SegmentDescription>();
123     switch (left.column()) {
124     case SegmentsModel::NameColumn:
125         return leftSegment.name < rightSegment.name;
126     case SegmentsModel::SizeColumn:
127         return leftSegment.size < rightSegment.size;
128     case SegmentsModel::AddressColumn:
129     case SegmentsModel::EndAddressColumn:
130         return leftSegment.vaddr < rightSegment.vaddr;
131     case SegmentsModel::CommentColumn:
132         return Core()->getCommentAt(leftSegment.vaddr) < Core()->getCommentAt(rightSegment.vaddr);
133     default:
134         break;
135     }
136     return false;
137 }
138 
SegmentsWidget(MainWindow * main)139 SegmentsWidget::SegmentsWidget(MainWindow *main) :
140     ListDockWidget(main)
141 {
142     setObjectName("SegmentsWidget");
143     setWindowTitle(QStringLiteral("Segments"));
144 
145     segmentsModel = new SegmentsModel(&segments, this);
146     auto proxyModel = new SegmentsProxyModel(segmentsModel, this);
147     setModels(proxyModel);
148 
149     ui->treeView->sortByColumn(SegmentsModel::NameColumn, Qt::AscendingOrder);
150 
151     ui->quickFilterView->closeFilter();
152     showCount(false);
153 
154     connect(Core(), &CutterCore::refreshAll, this, &SegmentsWidget::refreshSegments);
155     connect(Core(), &CutterCore::codeRebased, this, &SegmentsWidget::refreshSegments);
156     connect(Core(), &CutterCore::commentsChanged, this, [this]() {
157         qhelpers::emitColumnChanged(segmentsModel, SegmentsModel::CommentColumn);
158     });
159 }
160 
~SegmentsWidget()161 SegmentsWidget::~SegmentsWidget() {}
162 
refreshSegments()163 void SegmentsWidget::refreshSegments()
164 {
165     segmentsModel->beginResetModel();
166     segments = Core()->getAllSegments();
167     segmentsModel->endResetModel();
168 
169     qhelpers::adjustColumns(ui->treeView, SegmentsModel::ColumnCount, 0);
170 }
171