2018-05-03 07:52:30 +00:00
|
|
|
#include <QMenu>
|
|
|
|
#include <QSplitter>
|
|
|
|
#include <QTreeView>
|
|
|
|
#include <QResizeEvent>
|
|
|
|
|
|
|
|
#include "SectionsWidget.h"
|
|
|
|
#include "ui_SectionsWidget.h"
|
|
|
|
#include "PieView.h"
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-10-01 19:09:42 +00:00
|
|
|
#include "MainWindow.h"
|
|
|
|
#include "utils/Helpers.h"
|
2017-04-13 15:14:02 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
SectionsModel::SectionsModel(QList<SectionDescription> *sections, QObject *parent)
|
|
|
|
: QAbstractListModel(parent),
|
|
|
|
sections(sections)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int SectionsModel::rowCount(const QModelIndex &) const
|
|
|
|
{
|
|
|
|
return sections->count();
|
|
|
|
}
|
|
|
|
|
|
|
|
int SectionsModel::columnCount(const QModelIndex &) const
|
|
|
|
{
|
|
|
|
return SectionsModel::ColumnCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant SectionsModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
|
|
|
// TODO: create unique colors, e. g. use HSV color space and rotate in H for 360/size
|
|
|
|
static const QList<QColor> colors = { QColor("#1ABC9C"), //TURQUOISE
|
|
|
|
QColor("#2ECC71"), //EMERALD
|
|
|
|
QColor("#3498DB"), //PETER RIVER
|
|
|
|
QColor("#9B59B6"), //AMETHYST
|
|
|
|
QColor("#34495E"), //WET ASPHALT
|
|
|
|
QColor("#F1C40F"), //SUN FLOWER
|
|
|
|
QColor("#E67E22"), //CARROT
|
|
|
|
QColor("#E74C3C"), //ALIZARIN
|
|
|
|
QColor("#ECF0F1"), //CLOUDS
|
|
|
|
QColor("#BDC3C7"), //SILVER
|
|
|
|
QColor("#95A5A6") //COBCRETE
|
|
|
|
};
|
|
|
|
|
|
|
|
if (index.row() >= sections->count())
|
|
|
|
return QVariant();
|
|
|
|
|
|
|
|
const SectionDescription §ion = sections->at(index.row());
|
|
|
|
|
|
|
|
switch (role) {
|
|
|
|
case Qt::DisplayRole:
|
|
|
|
switch (index.column()) {
|
|
|
|
case SectionsModel::NameColumn:
|
|
|
|
return section.name;
|
|
|
|
case SectionsModel::SizeColumn:
|
|
|
|
return section.size;
|
|
|
|
case SectionsModel::AddressColumn:
|
|
|
|
return RAddressString(section.vaddr);
|
|
|
|
case SectionsModel::EndAddressColumn:
|
|
|
|
return RAddressString(section.vaddr + section.size);
|
2018-05-05 10:11:44 +00:00
|
|
|
case SectionsModel::EntropyColumn:
|
|
|
|
return section.entropy;
|
2018-05-03 07:52:30 +00:00
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
case Qt::DecorationRole:
|
|
|
|
if (index.column() == 0)
|
|
|
|
return colors[index.row() % colors.size()];
|
|
|
|
return QVariant();
|
|
|
|
case SectionsModel::SectionDescriptionRole:
|
|
|
|
return QVariant::fromValue(section);
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant SectionsModel::headerData(int section, Qt::Orientation, int role) const
|
|
|
|
{
|
|
|
|
switch (role) {
|
|
|
|
case Qt::DisplayRole:
|
|
|
|
switch (section) {
|
|
|
|
case SectionsModel::NameColumn:
|
|
|
|
return tr("Name");
|
|
|
|
case SectionsModel::SizeColumn:
|
|
|
|
return tr("Size");
|
|
|
|
case SectionsModel::AddressColumn:
|
|
|
|
return tr("Address");
|
|
|
|
case SectionsModel::EndAddressColumn:
|
|
|
|
return tr("EndAddress");
|
2018-05-05 10:11:44 +00:00
|
|
|
case SectionsModel::EntropyColumn:
|
|
|
|
return tr("Entropy");
|
2018-05-03 07:52:30 +00:00
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SectionsModel::beginReloadSections()
|
|
|
|
{
|
|
|
|
beginResetModel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SectionsModel::endReloadSections()
|
|
|
|
{
|
|
|
|
endResetModel();
|
|
|
|
// Update PieChart
|
|
|
|
emit dataChanged(QModelIndex(), QModelIndex());
|
|
|
|
}
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
SectionsProxyModel::SectionsProxyModel(SectionsModel *sourceModel, QObject *parent)
|
|
|
|
: QSortFilterProxyModel(parent)
|
|
|
|
{
|
|
|
|
setSourceModel(sourceModel);
|
|
|
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
|
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
|
|
|
connect(sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
|
|
|
|
this, SLOT(onSourceModelDataChanged(QModelIndex,QModelIndex,QVector<int>)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SectionsProxyModel::onSourceModelDataChanged(const QModelIndex &topLeft,
|
|
|
|
const QModelIndex &bottomRight,
|
|
|
|
const QVector<int> &roles)
|
|
|
|
{
|
|
|
|
// Pass the signal further to update PieChart
|
|
|
|
emit dataChanged(topLeft, bottomRight, roles);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SectionsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
|
|
|
{
|
|
|
|
auto leftSection = left.data(SectionsModel::SectionDescriptionRole).value<SectionDescription>();
|
|
|
|
auto rightSection = right.data(SectionsModel::SectionDescriptionRole).value<SectionDescription>();
|
|
|
|
|
|
|
|
switch (left.column()) {
|
|
|
|
case SectionsModel::NameColumn:
|
|
|
|
return leftSection.name < rightSection.name;
|
|
|
|
case SectionsModel::SizeColumn:
|
|
|
|
return leftSection.size < rightSection.size;
|
|
|
|
case SectionsModel::AddressColumn:
|
|
|
|
case SectionsModel::EndAddressColumn:
|
|
|
|
return leftSection.vaddr < rightSection.vaddr;
|
2018-05-05 10:11:44 +00:00
|
|
|
case SectionsModel::EntropyColumn:
|
|
|
|
return leftSection.entropy < rightSection.entropy;
|
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SectionsWidget::SectionsWidget(MainWindow *main, QAction *action) :
|
|
|
|
CutterDockWidget(main, action),
|
|
|
|
ui(new Ui::SectionsWidget),
|
2017-04-13 15:14:02 +00:00
|
|
|
main(main)
|
2017-03-29 10:18:37 +00:00
|
|
|
{
|
2018-05-03 07:52:30 +00:00
|
|
|
ui->setupUi(this);
|
|
|
|
|
|
|
|
sectionsModel = new SectionsModel(§ions, this);
|
|
|
|
sectionsProxyModel = new SectionsProxyModel(sectionsModel, this);
|
2017-04-09 17:09:35 +00:00
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
setupViews();
|
2017-11-19 12:56:10 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
2018-02-02 15:56:39 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
|
|
|
|
this, SLOT(showSectionsContextMenu(const QPoint &)));
|
2017-11-26 21:31:27 +00:00
|
|
|
|
2017-11-19 12:56:10 +00:00
|
|
|
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshSections()));
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
SectionsWidget::~SectionsWidget() {}
|
|
|
|
|
|
|
|
void SectionsWidget::resizeEvent(QResizeEvent *event)
|
|
|
|
{
|
|
|
|
if (main->responsive && isVisible()) {
|
|
|
|
if (event->size().width() >= event->size().height()) {
|
|
|
|
on_actionHorizontal_triggered();
|
|
|
|
} else {
|
|
|
|
on_actionVertical_triggered();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QWidget::resizeEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SectionsWidget::showSectionsContextMenu(const QPoint &pt)
|
2017-03-29 10:18:37 +00:00
|
|
|
{
|
2018-05-03 07:52:30 +00:00
|
|
|
// Set functions popup menu
|
|
|
|
QMenu *menu = new QMenu(this);
|
|
|
|
menu->clear();
|
|
|
|
menu->addAction(ui->actionHorizontal);
|
|
|
|
menu->addAction(ui->actionVertical);
|
2017-04-13 15:14:02 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
if (splitter->orientation() == 1) {
|
|
|
|
ui->actionHorizontal->setChecked(true);
|
|
|
|
ui->actionVertical->setChecked(false);
|
|
|
|
} else {
|
|
|
|
ui->actionVertical->setChecked(true);
|
|
|
|
ui->actionHorizontal->setChecked(false);
|
2017-04-13 15:14:02 +00:00
|
|
|
}
|
2017-05-03 09:09:57 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
menu->exec(mapToGlobal(pt));
|
|
|
|
delete menu;
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
2017-04-13 15:14:02 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
void SectionsWidget::refreshSections()
|
2017-03-29 10:18:37 +00:00
|
|
|
{
|
2018-05-03 07:52:30 +00:00
|
|
|
sectionsModel->beginReloadSections();
|
|
|
|
sections = Core()->getAllSections();
|
|
|
|
sectionsModel->endReloadSections();
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
qhelpers::adjustColumns(sectionsTable, SectionsModel::ColumnCount, 0);
|
|
|
|
}
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
void SectionsWidget::setupViews()
|
|
|
|
{
|
|
|
|
splitter = new QSplitter;
|
|
|
|
sectionsTable = new QTreeView;
|
|
|
|
sectionsPieChart = new PieView;
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
splitter->addWidget(sectionsTable);
|
|
|
|
splitter->addWidget(sectionsPieChart);
|
|
|
|
//splitter->setStretchFactor(0, 4);
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
sectionsTable->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
|
|
sectionsTable->setIndentation(10);
|
|
|
|
sectionsTable->setFrameShape(QFrame::NoFrame);
|
|
|
|
sectionsTable->setSortingEnabled(true);
|
|
|
|
sectionsTable->sortByColumn(SectionsModel::NameColumn, Qt::AscendingOrder);
|
|
|
|
connect(sectionsTable, SIGNAL(doubleClicked(const QModelIndex &)),
|
|
|
|
this, SLOT(onSectionsDoubleClicked(const QModelIndex &)));
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
sectionsPieChart->setFrameShape(QFrame::NoFrame);
|
|
|
|
sectionsPieChart->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
sectionsTable->setModel(sectionsProxyModel);
|
|
|
|
sectionsPieChart->setModel(sectionsProxyModel);
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
QItemSelectionModel *selectionModel = new QItemSelectionModel(sectionsProxyModel);
|
|
|
|
sectionsTable->setSelectionModel(selectionModel);
|
|
|
|
sectionsPieChart->setSelectionModel(selectionModel);
|
|
|
|
|
|
|
|
setWidget(splitter);
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
2018-02-02 15:56:39 +00:00
|
|
|
|
|
|
|
void SectionsWidget::onSectionsDoubleClicked(const QModelIndex &index)
|
|
|
|
{
|
2018-04-23 07:54:06 +00:00
|
|
|
if (!index.isValid())
|
|
|
|
return;
|
|
|
|
|
2018-05-03 07:52:30 +00:00
|
|
|
auto section = index.data(SectionsModel::SectionDescriptionRole).value<SectionDescription>();
|
|
|
|
Core()->seek(section.vaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SectionsWidget::on_actionVertical_triggered()
|
|
|
|
{
|
|
|
|
splitter->setOrientation(Qt::Vertical);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SectionsWidget::on_actionHorizontal_triggered()
|
|
|
|
{
|
|
|
|
splitter->setOrientation(Qt::Horizontal);
|
2018-02-02 15:56:39 +00:00
|
|
|
}
|