3944 lines
97 KiB
C++
3944 lines
97 KiB
C++
#include "../core/objects.h"
|
||
#include "../core/files.h"
|
||
#include "../core/core.h"
|
||
#include "../core/processors.h"
|
||
#include "../core/script.h"
|
||
#include "../core/lang.h"
|
||
|
||
#include "models.h"
|
||
#include "moc/moc_models.cc"
|
||
#include "widgets.h"
|
||
#include "property_editor.h"
|
||
#include "message_dialog.h"
|
||
|
||
static QIcon nodeIcon(NodeType type, bool is_disabled = false)
|
||
{
|
||
QString iconName;
|
||
switch (type) {
|
||
case NODE_FUNCTIONS:
|
||
iconName = ":/images/star.png";
|
||
break;
|
||
case NODE_LICENSES:
|
||
iconName = ":/images/key.png";
|
||
break;
|
||
case NODE_SCRIPT:
|
||
iconName = ":/images/script.png";
|
||
break;
|
||
case NODE_OPTIONS:
|
||
iconName = ":/images/gear.png";
|
||
break;
|
||
case NODE_FILES:
|
||
case NODE_ASSEMBLIES:
|
||
iconName = ":/images/box.png";
|
||
break;
|
||
case NODE_ARCHITECTURE:
|
||
iconName = ":/images/processor.png";
|
||
break;
|
||
case NODE_LOAD_COMMANDS:
|
||
iconName = ":/images/lightning.png";
|
||
break;
|
||
case NODE_SEGMENTS:
|
||
iconName = ":/images/code.png";
|
||
break;
|
||
case NODE_EXPORTS:
|
||
iconName = ":/images/export.png";
|
||
break;
|
||
case NODE_IMPORTS:
|
||
iconName = ":/images/import.png";
|
||
break;
|
||
case NODE_RESOURCES:
|
||
iconName = ":/images/database.png";
|
||
break;
|
||
case NODE_CALC:
|
||
iconName = ":/images/calc.png";
|
||
break;
|
||
case NODE_DUMP:
|
||
iconName = ":/images/dump.png";
|
||
break;
|
||
case NODE_LICENSE:
|
||
iconName = ":/images/item_key.png";
|
||
break;
|
||
case NODE_FILE:
|
||
iconName = ":/images/item_file.png";
|
||
break;
|
||
case NODE_PROPERTY:
|
||
iconName = ":/images/item_property.png";
|
||
break;
|
||
case NODE_LOAD_COMMAND:
|
||
iconName = ":/images/item_load_command.png";
|
||
break;
|
||
case NODE_SEGMENT:
|
||
case NODE_SECTION:
|
||
iconName = ":/images/item_code.png";
|
||
break;
|
||
case NODE_IMPORT_FUNCTION:
|
||
iconName = ":/images/item_import.png";
|
||
break;
|
||
case NODE_EXPORT:
|
||
iconName = ":/images/item_export.png";
|
||
break;
|
||
case NODE_RESOURCE:
|
||
iconName = ":/images/item_resource.png";
|
||
break;
|
||
case NODE_WATERMARK:
|
||
case NODE_FUNCTION:
|
||
iconName = ":/images/item.png";
|
||
break;
|
||
case NODE_SCRIPT_BOOKMARK:
|
||
iconName = ":/images/item_code.png";
|
||
break;
|
||
case NODE_FOLDER:
|
||
case NODE_RESOURCE_FOLDER:
|
||
case NODE_MAP_FOLDER:
|
||
case NODE_IMPORT_FOLDER:
|
||
case NODE_EXPORT_FOLDER:
|
||
case NODE_IMPORT:
|
||
case NODE_FILE_FOLDER:
|
||
if (is_disabled) {
|
||
QIcon res;
|
||
QPixmap firstImage(":/images/folder_close.png");
|
||
QPixmap secondImage(":/images/bullet_delete.png");
|
||
{
|
||
QPainter painter(&firstImage);
|
||
painter.drawPixmap(firstImage.width() - secondImage.width(), firstImage.height() - secondImage.height(), secondImage);
|
||
}
|
||
res.addPixmap(firstImage);
|
||
|
||
firstImage = QPixmap(":/images/folder.png");
|
||
{
|
||
QPainter painter(&firstImage);
|
||
painter.drawPixmap(firstImage.width() - secondImage.width(), firstImage.height() - secondImage.height(), secondImage);
|
||
}
|
||
res.addPixmap(firstImage, QIcon::Normal, QIcon::On);
|
||
|
||
return res;
|
||
} else {
|
||
QIcon res = QIcon(":/images/folder_close.png");
|
||
res.addPixmap(QPixmap(":/images/folder.png"), QIcon::Normal, QIcon::On);
|
||
return res;
|
||
}
|
||
break;
|
||
}
|
||
|
||
if (is_disabled) {
|
||
QPixmap firstImage(iconName);
|
||
QPixmap secondImage(":/images/bullet_delete.png");
|
||
QPainter painter(&firstImage);
|
||
painter.drawPixmap(firstImage.width() - secondImage.width(), firstImage.height() - secondImage.height(), secondImage);
|
||
|
||
return QIcon(firstImage);
|
||
} else {
|
||
return QIcon(iconName);
|
||
}
|
||
}
|
||
|
||
template<typename F>
|
||
static QIcon functionIcon(F *func)
|
||
{
|
||
if (!func || !func->need_compile())
|
||
return nodeIcon(NODE_FUNCTION, true);
|
||
|
||
QString iconName;
|
||
switch (func->compilation_type()) {
|
||
case ctMutation:
|
||
iconName = ":/images/item_m.png";
|
||
break;
|
||
case ctUltra:
|
||
iconName = ":/images/item_u.png";
|
||
break;
|
||
default:
|
||
iconName = ":/images/item_v.png";
|
||
break;
|
||
}
|
||
|
||
QString bullet_name;
|
||
if (func->type() == otUnknown)
|
||
bullet_name = ":/images/bullet_warning.png";
|
||
else if (func->compilation_type() != ctMutation && (func->compilation_options() & coLockToKey))
|
||
bullet_name = ":/images/bullet_key.png";
|
||
|
||
if (!bullet_name.isEmpty()) {
|
||
QPixmap firstImage(iconName);
|
||
QPixmap secondImage(bullet_name);
|
||
QPainter painter(&firstImage);
|
||
painter.drawPixmap(firstImage.width() - secondImage.width(), firstImage.height() - secondImage.height(), secondImage);
|
||
|
||
QIcon res;
|
||
res.addPixmap(firstImage);
|
||
return res;
|
||
}
|
||
return QIcon(iconName);
|
||
}
|
||
|
||
/**
|
||
* ProjectNode
|
||
*/
|
||
|
||
ProjectNode::ProjectNode(ProjectNode *parent, NodeType type, void *data)
|
||
: parent_(NULL), data_(data), type_(type), properties_(NULL)
|
||
{
|
||
if (parent)
|
||
parent->addChild(this);
|
||
}
|
||
|
||
void ProjectNode::clear()
|
||
{
|
||
for (int i = 0; i < children_.size(); i++) {
|
||
ProjectNode *node = children_[i];
|
||
node->parent_ = NULL;
|
||
delete node;
|
||
}
|
||
children_.clear();
|
||
|
||
if (properties_) {
|
||
delete properties_;
|
||
properties_ = NULL;
|
||
}
|
||
}
|
||
|
||
ProjectNode::~ProjectNode()
|
||
{
|
||
clear();
|
||
if (parent_)
|
||
parent_->removeChild(this);
|
||
}
|
||
|
||
QString functionProtection(const FunctionBundle *func)
|
||
{
|
||
return func ? QString::fromUtf8(func->display_protection().c_str()) : QString::fromUtf8(language[lsNone].c_str());
|
||
}
|
||
|
||
bool ProjectNode::contains(const QRegExp &filter) const
|
||
{
|
||
for (int i = 0; i < 2; i++) {
|
||
if (text(i).contains(filter))
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
QString ProjectNode::text(int column) const
|
||
{
|
||
if (column == 0)
|
||
return text_;
|
||
|
||
switch (type_) {
|
||
case NODE_SCRIPT:
|
||
case NODE_SCRIPT_BOOKMARK:
|
||
{
|
||
Script *object = static_cast<Script *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(object->text().c_str());
|
||
}
|
||
}
|
||
break;
|
||
case NODE_FUNCTION:
|
||
{
|
||
FunctionBundle *object = static_cast<FunctionBundle *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(object->display_address().c_str());
|
||
} else if (column == 2) {
|
||
return QString::fromUtf8(object->display_protection().c_str());
|
||
}
|
||
}
|
||
break;
|
||
case NODE_MAP_FUNCTION:
|
||
{
|
||
MapFunctionBundle *object = static_cast<MapFunctionBundle *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(object->display_address().c_str());
|
||
} else if (column == 2) {
|
||
IFile *file = object->owner()->owner();
|
||
return functionProtection(file->function_list()->GetFunctionByName(object->name()));
|
||
}
|
||
}
|
||
break;
|
||
case NODE_LOAD_COMMAND:
|
||
{
|
||
ILoadCommand *object = static_cast<ILoadCommand *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str());
|
||
} else if (column == 2) {
|
||
return QString::fromUtf8(DisplayValue(osDWord, object->size()).c_str());
|
||
}
|
||
}
|
||
break;
|
||
case NODE_SEGMENT:
|
||
case NODE_SECTION:
|
||
{
|
||
ISection *object = static_cast<ISection *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str());
|
||
} else if (column == 2) {
|
||
return QString::fromUtf8(DisplayValue(osDWord, object->size()).c_str());
|
||
} else if (column == 3) {
|
||
return QString::fromUtf8(DisplayValue(osDWord, object->physical_offset()).c_str());
|
||
} else if (column == 4) {
|
||
return QString::fromUtf8(DisplayValue(osDWord, object->physical_size()).c_str());
|
||
} else if (column == 5) {
|
||
return QString::fromUtf8(DisplayValue(osDWord, object->flags()).c_str());
|
||
}
|
||
}
|
||
break;
|
||
case NODE_RESOURCE:
|
||
{
|
||
IResource *object = static_cast<IResource *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str());
|
||
} else if (column == 2) {
|
||
return QString::fromUtf8(DisplayValue(osDWord, object->size()).c_str());
|
||
}
|
||
}
|
||
break;
|
||
case NODE_IMPORT_FUNCTION:
|
||
{
|
||
IImportFunction *object = static_cast<IImportFunction *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str());
|
||
}
|
||
}
|
||
break;
|
||
case NODE_EXPORT:
|
||
{
|
||
IExport *object = static_cast<IExport *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str());
|
||
}
|
||
}
|
||
break;
|
||
case NODE_PROPERTY:
|
||
{
|
||
Property *object = static_cast<Property *>(data_);
|
||
if (column == 1) {
|
||
return object->valueText();
|
||
}
|
||
}
|
||
break;
|
||
#ifdef ULTIMATE
|
||
case NODE_LICENSE:
|
||
{
|
||
License *object = static_cast<License *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(object->customer_email().c_str());
|
||
} else if (column == 2) {
|
||
LicenseDate date = object->date();
|
||
return QDate(date.Year, date.Month, date.Day).toString(Qt::SystemLocaleShortDate);
|
||
}
|
||
}
|
||
break;
|
||
case NODE_FILE:
|
||
{
|
||
InternalFile *object = static_cast<InternalFile *>(data_);
|
||
if (column == 1) {
|
||
return QString::fromUtf8(object->file_name().c_str());
|
||
}
|
||
}
|
||
break;
|
||
#endif
|
||
}
|
||
return QString();
|
||
}
|
||
|
||
QString ProjectNode::path() const
|
||
{
|
||
QString res;
|
||
for (ProjectNode *p = parent(); p && p->type() != NODE_ROOT; p = p->parent()) {
|
||
if (!res.isEmpty())
|
||
res = " > " + res;
|
||
res = p->text() + res;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
void ProjectNode::addChild(ProjectNode *child)
|
||
{
|
||
insertChild(childCount(), child);
|
||
}
|
||
|
||
void ProjectNode::insertChild(int index, ProjectNode *child)
|
||
{
|
||
if (child->parent())
|
||
return;
|
||
|
||
child->parent_ = this;
|
||
children_.insert(index, child);
|
||
}
|
||
|
||
void ProjectNode::removeChild(ProjectNode *child)
|
||
{
|
||
if (children_.removeOne(child))
|
||
child->parent_ = NULL;
|
||
}
|
||
|
||
void ProjectNode::setPropertyManager(PropertyManager *propertyManager)
|
||
{
|
||
if (properties_) {
|
||
delete properties_;
|
||
properties_ = NULL;
|
||
}
|
||
|
||
if (!propertyManager)
|
||
return;
|
||
|
||
properties_ = new ProjectNode(NULL, type_, data_);
|
||
properties_->setText(text_);
|
||
properties_->setIcon(nodeIcon(type_));
|
||
|
||
QList<Property *> propertyList;
|
||
QMap<Property *, ProjectNode *> propertyMap;
|
||
propertyMap[propertyManager->root()] = properties_;
|
||
propertyList.append(propertyManager->root()->children());
|
||
for (int i = 0; i < propertyList.size(); i++) {
|
||
Property *prop = propertyList[i];
|
||
propertyList.append(prop->children());
|
||
|
||
ProjectNode *node = new ProjectNode(propertyMap[prop->parent()], NODE_PROPERTY, prop);
|
||
node->setText(prop->name());
|
||
node->setIcon(nodeIcon(node->type()));
|
||
propertyMap[prop] = node;
|
||
}
|
||
}
|
||
|
||
void ProjectNode::localize()
|
||
{
|
||
switch (type_) {
|
||
case NODE_FUNCTIONS:
|
||
setText(QString::fromUtf8(language[lsFunctionsForProtection].c_str()));
|
||
break;
|
||
case NODE_LICENSES:
|
||
setText(QString::fromUtf8(language[lsLicenses].c_str()));
|
||
break;
|
||
case NODE_FILES:
|
||
setText(QString::fromUtf8(language[lsFiles].c_str()));
|
||
break;
|
||
case NODE_ASSEMBLIES:
|
||
setText(QString::fromUtf8(language[lsAssemblies].c_str()));
|
||
break;
|
||
case NODE_SCRIPT:
|
||
setText(QString::fromUtf8(language[lsScript].c_str()));
|
||
break;
|
||
case NODE_OPTIONS:
|
||
setText(QString::fromUtf8(language[lsOptions].c_str()));
|
||
break;
|
||
case NODE_PROPERTY:
|
||
setText(static_cast<Property*>(data_)->name());
|
||
break;
|
||
case NODE_LOAD_COMMANDS:
|
||
setText(QString::fromUtf8(language[lsDirectories].c_str()));
|
||
break;
|
||
case NODE_SEGMENTS:
|
||
setText(QString::fromUtf8(language[lsSegments].c_str()));
|
||
break;
|
||
case NODE_IMPORTS:
|
||
setText(QString::fromUtf8(language[lsImports].c_str()));
|
||
break;
|
||
case NODE_EXPORTS:
|
||
setText(QString::fromUtf8(language[lsExports].c_str()));
|
||
break;
|
||
case NODE_RESOURCES:
|
||
setText(QString::fromUtf8(language[lsResources].c_str()));
|
||
break;
|
||
case NODE_CALC:
|
||
setText(QString::fromUtf8(language[lsCalculator].c_str()));
|
||
break;
|
||
case NODE_DUMP:
|
||
setText(QString::fromUtf8(language[lsDump].c_str()));
|
||
break;
|
||
case NODE_ARCHITECTURE:
|
||
for (int i = 0; i < childCount(); i++) {
|
||
child(i)->localize();
|
||
}
|
||
}
|
||
|
||
if (properties_) {
|
||
QList<ProjectNode *> list;
|
||
list.append(properties_);
|
||
for (int i = 0; i < list.size(); i++) {
|
||
ProjectNode *node = list[i];
|
||
node->localize();
|
||
|
||
list.append(node->children());
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* BaseModel
|
||
*/
|
||
|
||
BaseModel::BaseModel(QObject *parent)
|
||
: QAbstractItemModel(parent), root_(NULL), core_(NULL)
|
||
{
|
||
root_ = new ProjectNode(NULL, NODE_ROOT);
|
||
}
|
||
|
||
BaseModel::~BaseModel()
|
||
{
|
||
delete root_;
|
||
}
|
||
|
||
ProjectNode *BaseModel::indexToNode(const QModelIndex &index) const
|
||
{
|
||
if (index.isValid())
|
||
return static_cast<ProjectNode *>(index.internalPointer());
|
||
return root_;
|
||
}
|
||
|
||
QModelIndex BaseModel::parent(const QModelIndex &index) const
|
||
{
|
||
if (!index.isValid())
|
||
return QModelIndex();
|
||
|
||
ProjectNode *childNode = indexToNode(index);
|
||
ProjectNode *parentNode = childNode->parent();
|
||
if (parentNode == root_)
|
||
return QModelIndex();
|
||
|
||
return createIndex(parentNode->parent()->children().indexOf(parentNode), 0, parentNode);
|
||
}
|
||
|
||
int BaseModel::columnCount(const QModelIndex & /* parent */) const
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
int BaseModel::rowCount(const QModelIndex &parent) const
|
||
{
|
||
ProjectNode *parentNode = indexToNode(parent);
|
||
return parentNode->childCount();
|
||
}
|
||
|
||
QVariant BaseModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if (!index.isValid())
|
||
return QVariant();
|
||
|
||
ProjectNode *node = indexToNode(index);
|
||
switch (role) {
|
||
case Qt::DisplayRole:
|
||
return node->text();
|
||
case Qt::DecorationRole:
|
||
return node->icon();
|
||
case Qt::FontRole:
|
||
{
|
||
switch (node->type()) {
|
||
case NODE_MAP_FUNCTION:
|
||
case NODE_WATERMARK:
|
||
case NODE_MESSAGE:
|
||
case NODE_WARNING:
|
||
case NODE_ERROR:
|
||
case NODE_TEMPLATE:
|
||
break;
|
||
default:
|
||
if (node->parent()->type() == NODE_ROOT) {
|
||
QFont font;
|
||
font.setBold(true);
|
||
return font;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case Qt::BackgroundColorRole:
|
||
if (node->type() == NODE_WARNING)
|
||
return QColor(0xff, 0xf8, 0xe3);
|
||
else if (node->type() == NODE_ERROR)
|
||
return QColor(0xff, 0xf6, 0xf4);
|
||
break;
|
||
case Qt::TextColorRole:
|
||
if (node->type() == NODE_ERROR)
|
||
return QColor(0xff, 0x3c, 0x08);
|
||
break;
|
||
case Qt::Vmp::StaticTextRole:
|
||
{
|
||
int size = 0;
|
||
switch (node->type())
|
||
{
|
||
case NODE_FUNCTIONS:
|
||
size = (int)reinterpret_cast<FunctionBundleList*>(node->data())->count();
|
||
break;
|
||
case NODE_MAP_FOLDER:
|
||
if (node->parent()->type() == NODE_ROOT) {
|
||
QList<ProjectNode *> nodeList = node->children();
|
||
for (int i = 0; i < nodeList.size(); i++) {
|
||
ProjectNode *child = nodeList[i];
|
||
if (child->type() == NODE_MAP_FOLDER)
|
||
nodeList.append(child->children());
|
||
else
|
||
size++;
|
||
}
|
||
break;
|
||
}
|
||
case NODE_FOLDER:
|
||
case NODE_IMPORT_FOLDER:
|
||
case NODE_EXPORT_FOLDER:
|
||
case NODE_FILE_FOLDER:
|
||
{
|
||
QListIterator<ProjectNode *> i(node->children());
|
||
while (i.hasNext()) {
|
||
NodeType childType = i.next()->type();
|
||
if (childType != NODE_FOLDER && childType != NODE_MAP_FOLDER && childType != NODE_FILE_FOLDER)
|
||
size++;
|
||
}
|
||
}
|
||
break;
|
||
case NODE_RESOURCE_FOLDER:
|
||
case NODE_IMPORT:
|
||
case NODE_IMPORTS:
|
||
case NODE_EXPORTS:
|
||
case NODE_SEGMENTS:
|
||
case NODE_RESOURCES:
|
||
case NODE_LICENSES:
|
||
case NODE_LOAD_COMMANDS:
|
||
case NODE_SEGMENT:
|
||
size = node->childCount();
|
||
break;
|
||
#ifdef ULTIMATE
|
||
case NODE_FILES:
|
||
case NODE_ASSEMBLIES:
|
||
size = (int)reinterpret_cast<FileManager*>(node->data())->count();
|
||
break;
|
||
#endif
|
||
case NODE_WATERMARK:
|
||
size = (int)reinterpret_cast<Watermark*>(node->data())->use_count();
|
||
break;
|
||
}
|
||
if (size > 0)
|
||
return QString("(%1)").arg(size);
|
||
}
|
||
break;
|
||
case Qt::Vmp::StaticColorRole:
|
||
return QColor(0x9b, 0xa2, 0xaa);
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
QModelIndex BaseModel::nodeToIndex(ProjectNode *node) const
|
||
{
|
||
if (!node || node == root_)
|
||
return QModelIndex();
|
||
|
||
return createIndex(node->parent()->children().indexOf(node), 0, node);
|
||
}
|
||
|
||
QModelIndex BaseModel::index(int row, int column, const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid() && parent.column() != 0)
|
||
return QModelIndex();
|
||
|
||
ProjectNode *parentNode = indexToNode(parent);
|
||
ProjectNode *childNode = parentNode->children().value(row);
|
||
if (!childNode)
|
||
return QModelIndex();
|
||
|
||
return createIndex(row, column, childNode);
|
||
}
|
||
|
||
void BaseModel::setCore(Core *core)
|
||
{
|
||
clear();
|
||
core_ = core;
|
||
}
|
||
|
||
void BaseModel::clear()
|
||
{
|
||
root_->clear();
|
||
objectToNode_.clear();
|
||
}
|
||
|
||
void BaseModel::setObjectNode(void *object, ProjectNode *node)
|
||
{
|
||
objectToNode_[object] = node;
|
||
}
|
||
|
||
QModelIndex BaseModel::objectToIndex(void *object) const
|
||
{
|
||
return nodeToIndex(objectToNode(object));
|
||
}
|
||
|
||
ProjectNode *BaseModel::objectToNode(void *object) const
|
||
{
|
||
return objectToNode_[object];
|
||
}
|
||
|
||
bool BaseModel::removeNode(void *object)
|
||
{
|
||
ProjectNode *node = objectToNode(object);
|
||
if (!node)
|
||
return false;
|
||
|
||
removeObject(object);
|
||
|
||
ProjectNode *parent = node->parent();
|
||
int i = parent->children().indexOf(node);
|
||
beginRemoveRows(nodeToIndex(parent), i, i);
|
||
emit nodeRemoved(node);
|
||
delete node;
|
||
endRemoveRows();
|
||
return true;
|
||
}
|
||
|
||
void BaseModel::updateNode(ProjectNode *node)
|
||
{
|
||
QModelIndex index = nodeToIndex(node);
|
||
dataChanged(index, index);
|
||
emit nodeUpdated(node);
|
||
}
|
||
|
||
void BaseModel::removeObject(void *object)
|
||
{
|
||
objectToNode_.remove(object);
|
||
emit objectRemoved(object);
|
||
}
|
||
|
||
void BaseModel::createFunctionsTree(ProjectNode *root)
|
||
{
|
||
size_t i, count;
|
||
int k, j;
|
||
QList<QString> classList;
|
||
QList<QString> delimList;
|
||
QList<ProjectNode *> folderList;
|
||
QMap<ProjectNode *, QString> delimMap;
|
||
QMap<QString, ProjectNode *> classMap;
|
||
NodeType folder_type;
|
||
QString delim;
|
||
ushort u;
|
||
ProjectNode *folder, *node, *child;
|
||
MapFunctionBundleList *map_function_list = NULL;
|
||
IImport *import = NULL;
|
||
IExportList *export_list = NULL;
|
||
|
||
switch (root->type()) {
|
||
#ifdef LITE
|
||
case NODE_FUNCTIONS:
|
||
#else
|
||
case NODE_ROOT:
|
||
#endif
|
||
if (!core()->input_file())
|
||
return;
|
||
map_function_list = core()->input_file()->map_function_list();
|
||
count = map_function_list->count();
|
||
folder_type = NODE_MAP_FOLDER;
|
||
break;
|
||
case NODE_IMPORT:
|
||
import = static_cast<IImport*>(root->data());
|
||
count = import->count();
|
||
folder_type = NODE_IMPORT_FOLDER;
|
||
break;
|
||
case NODE_EXPORTS:
|
||
export_list = static_cast<IExportList*>(root->data());
|
||
count = export_list->count();
|
||
folder_type = NODE_EXPORT_FOLDER;
|
||
break;
|
||
default:
|
||
return;
|
||
}
|
||
|
||
for (i = 0; i < count; i++) {
|
||
MapFunctionBundle *func = NULL;
|
||
IImportFunction *import_func = NULL;
|
||
IExport *export_func = NULL;
|
||
QString funcName;
|
||
|
||
switch (root->type()) {
|
||
#ifdef LITE
|
||
case NODE_FUNCTIONS:
|
||
#else
|
||
case NODE_ROOT:
|
||
#endif
|
||
func = map_function_list->item(i);
|
||
if (!func->is_code())
|
||
continue;
|
||
funcName = QString::fromUtf8(func->display_name(false).c_str());
|
||
break;
|
||
case NODE_IMPORT:
|
||
import_func = import->item(i);
|
||
funcName = QString::fromUtf8(import_func->display_name(false).c_str());
|
||
break;
|
||
case NODE_EXPORTS:
|
||
export_func = export_list->item(i);
|
||
funcName = QString::fromUtf8(export_func->display_name(false).c_str());
|
||
break;
|
||
}
|
||
|
||
size_t c = 0;
|
||
int p = 0;
|
||
classList.clear();
|
||
delimList.clear();
|
||
delim.clear();
|
||
for (k = 0; k < funcName.size(); k++) {
|
||
u = funcName[k].unicode();
|
||
switch (u) {
|
||
case '<':
|
||
c++;
|
||
break;
|
||
case '>':
|
||
c--;
|
||
break;
|
||
case ':':
|
||
if (c == 0 && k > 0 && funcName[k - 1].unicode() == ':') {
|
||
if (funcName[p] == '`')
|
||
p++;
|
||
classList.push_back(funcName.mid(p, k - p - 1));
|
||
delimList.push_back(delim);
|
||
delim = "::";
|
||
p = k + 1;
|
||
}
|
||
break;
|
||
case '.':
|
||
if (c == 0 && k > 0 && funcName[k - 1].unicode() != ':') {
|
||
classList.push_back(funcName.mid(p, k - p));
|
||
delimList.push_back(delim);
|
||
delim = QChar(u);
|
||
p = k + 1;
|
||
}
|
||
break;
|
||
case '/':
|
||
if (c == 0 && k > 0) {
|
||
classList.push_back(funcName.mid(p, k - p));
|
||
delimList.push_back(delim);
|
||
delim = QChar(u);
|
||
p = k + 1;
|
||
}
|
||
break;
|
||
case ' ':
|
||
if (c == 0)
|
||
p = k + 1;
|
||
break;
|
||
case '(':
|
||
case '"':
|
||
k = funcName.size();
|
||
break;
|
||
}
|
||
}
|
||
|
||
folder = root;
|
||
QString fullClassName;
|
||
for (k = 0; k < classList.size(); k++) {
|
||
QString className = classList[k];
|
||
delim = delimList[k];
|
||
fullClassName = fullClassName + delim + className;
|
||
|
||
ProjectNode *classFolder;
|
||
auto it = classMap.upperBound(fullClassName);
|
||
if (it != classMap.begin() && (it - 1).key() == fullClassName)
|
||
classFolder = (it - 1).value();
|
||
else {
|
||
classFolder = new ProjectNode(NULL, folder_type);
|
||
if (it == classMap.end()) {
|
||
for (j = 0; j < folder->childCount(); j++) {
|
||
if (folder->child(j)->type() != folder_type)
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
j = folder->children().indexOf(*it);
|
||
folder->insertChild(j, classFolder);
|
||
classFolder->setText(className);
|
||
classFolder->setIcon(nodeIcon(classFolder->type()));
|
||
|
||
delimMap[classFolder] = delim;
|
||
classMap[fullClassName] = classFolder;
|
||
}
|
||
folder = classFolder;
|
||
}
|
||
|
||
switch (root->type()) {
|
||
#ifdef LITE
|
||
case NODE_FUNCTIONS:
|
||
#else
|
||
case NODE_ROOT:
|
||
#endif
|
||
{
|
||
node = new ProjectNode(folder, NODE_MAP_FUNCTION, func);
|
||
node->setText(QString::fromUtf8(func->display_name().c_str()));
|
||
node->setIcon(functionIcon(core()->input_file()->function_list()->GetFunctionByName(func->name())));
|
||
setObjectNode(func, node);
|
||
}
|
||
break;
|
||
case NODE_IMPORT:
|
||
{
|
||
node = new ProjectNode(folder, NODE_IMPORT_FUNCTION, import_func);
|
||
node->setText(QString::fromUtf8(import_func->display_name().c_str()));
|
||
node->setIcon(nodeIcon(node->type()));
|
||
setObjectNode(import_func, node);
|
||
}
|
||
break;
|
||
case NODE_EXPORTS:
|
||
{
|
||
node = new ProjectNode(folder, NODE_EXPORT, export_func);
|
||
node->setText(QString::fromUtf8(export_func->display_name().c_str()));
|
||
node->setIcon(nodeIcon(node->type()));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// optimize
|
||
folderList.push_back(root);
|
||
for (k = 0; k < folderList.size(); k++) {
|
||
folder = folderList[k];
|
||
if (folder->childCount() == 1 && folder->child(0)->type() == folder_type) {
|
||
child = folder->child(0);
|
||
while (child->childCount()) {
|
||
node = child->child(0);
|
||
child->removeChild(node);
|
||
folder->addChild(node);
|
||
}
|
||
folder->setText(folder->text() + delimMap[child] + child->text());
|
||
|
||
delete child;
|
||
j = folderList.indexOf(child);
|
||
if (j != -1)
|
||
folderList[j] = folder;
|
||
}
|
||
}
|
||
}
|
||
|
||
void BaseModel::localize()
|
||
{
|
||
if (isEmpty())
|
||
return;
|
||
|
||
QList<ProjectNode*> nodes = root()->children();
|
||
if (nodes.isEmpty())
|
||
nodes.append(root());
|
||
|
||
for (int i = 0; i < nodes.count(); i++) {
|
||
ProjectNode *node = nodes[i];
|
||
node->localize();
|
||
updateNode(node);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* ProjectModel
|
||
*/
|
||
|
||
ProjectModel::ProjectModel(QObject *parent)
|
||
: BaseModel(parent), nodeFunctions_(NULL),
|
||
#ifdef ULTIMATE
|
||
nodeLicenses_(NULL), nodeFiles_(NULL),
|
||
#endif
|
||
#ifndef LITE
|
||
nodeScript_(NULL),
|
||
#endif
|
||
nodeOptions_(NULL)
|
||
{
|
||
|
||
}
|
||
|
||
ProjectModel::~ProjectModel()
|
||
{
|
||
|
||
}
|
||
|
||
Qt::ItemFlags ProjectModel::flags(const QModelIndex &index) const
|
||
{
|
||
Qt::ItemFlags res = QAbstractItemModel::flags(index);
|
||
if (res & Qt::ItemIsSelectable) {
|
||
ProjectNode *node = indexToNode(index);
|
||
if (node) {
|
||
if (node->type() == NODE_FOLDER || node->type() == NODE_FUNCTION || node->type() == NODE_FILE_FOLDER || node->type() == NODE_FILE)
|
||
res |= Qt::ItemIsDragEnabled;
|
||
if (node->type() == NODE_FUNCTIONS || node->type() == NODE_FOLDER || node->type() == NODE_FILES || node->type() == NODE_FILE_FOLDER || node->type() == NODE_ASSEMBLIES)
|
||
res |= Qt::ItemIsDropEnabled;
|
||
if ((node->type() == NODE_FOLDER && !static_cast<Folder *>(node->data())->read_only()) || node->type() == NODE_LICENSE || node->type() == NODE_FILE_FOLDER || node->type() == NODE_FILE)
|
||
res |= Qt::ItemIsEditable;
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
QStringList ProjectModel::mimeTypes() const
|
||
{
|
||
return QStringList() << QLatin1String("application/x-projectmodeldatalist");
|
||
}
|
||
|
||
QMimeData *ProjectModel::mimeData(const QModelIndexList &indexes) const
|
||
{
|
||
if (indexes.count() <= 0)
|
||
return 0;
|
||
QStringList types = mimeTypes();
|
||
if (types.isEmpty())
|
||
return 0;
|
||
QMimeData *data = new QMimeData();
|
||
QString format = types.at(0);
|
||
QByteArray encoded;
|
||
QDataStream stream(&encoded, QIODevice::WriteOnly);
|
||
for (QModelIndexList::ConstIterator it = indexes.begin(); it != indexes.end(); ++it) {
|
||
ProjectNode *node = indexToNode(*it);
|
||
if (!node)
|
||
continue;
|
||
|
||
stream << node->type();
|
||
switch (node->type()) {
|
||
case NODE_FUNCTION:
|
||
{
|
||
FunctionBundle *func = reinterpret_cast<FunctionBundle *>(node->data());
|
||
stream << QString::fromUtf8(func->id().c_str());
|
||
}
|
||
break;
|
||
case NODE_FOLDER:
|
||
{
|
||
Folder *folder = reinterpret_cast<Folder *>(node->data());
|
||
stream << QString::fromUtf8(folder->id().c_str());
|
||
}
|
||
break;
|
||
#ifdef ULTIMATE
|
||
case NODE_FILE_FOLDER:
|
||
{
|
||
FileFolder *folder = reinterpret_cast<FileFolder *>(node->data());
|
||
stream << QString::fromUtf8(folder->id().c_str());
|
||
}
|
||
break;
|
||
case NODE_FILE:
|
||
{
|
||
InternalFile *file = reinterpret_cast<InternalFile *>(node->data());
|
||
stream << (int)file->id();
|
||
}
|
||
break;
|
||
#endif
|
||
}
|
||
}
|
||
data->setData(format, encoded);
|
||
return data;
|
||
}
|
||
|
||
bool ProjectModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex &parent)
|
||
{
|
||
if (!data || !(action == Qt::CopyAction || action == Qt::MoveAction))
|
||
return false;
|
||
QStringList types = mimeTypes();
|
||
if (types.isEmpty())
|
||
return false;
|
||
QString format = types.at(0);
|
||
if (!data->hasFormat(format))
|
||
return false;
|
||
ProjectNode *dst = indexToNode(parent);
|
||
if (!dst)
|
||
return false;
|
||
|
||
if (dst->type()== NODE_FILES || dst->type() == NODE_ASSEMBLIES || dst->type()== NODE_FILE_FOLDER || dst->type()== NODE_FILE) {
|
||
#ifdef ULTIMATE
|
||
FileFolder *dst_folder;
|
||
switch (dst->type()) {
|
||
case NODE_FILE:
|
||
dst_folder = reinterpret_cast<InternalFile *>(dst->data())->folder();
|
||
break;
|
||
case NODE_FILE_FOLDER:
|
||
dst_folder = reinterpret_cast<FileFolder *>(dst->data());
|
||
break;
|
||
case NODE_FILES:
|
||
case NODE_ASSEMBLIES:
|
||
dst_folder = NULL;
|
||
break;
|
||
default:
|
||
return false;
|
||
}
|
||
QByteArray encoded = data->data(format);
|
||
QDataStream stream(&encoded, QIODevice::ReadOnly);
|
||
while (!stream.atEnd()) {
|
||
int t;
|
||
stream >> t;
|
||
switch (t) {
|
||
case NODE_FILE:
|
||
{
|
||
int id;
|
||
stream >> id;
|
||
InternalFile *file = core()->file_manager()->item((size_t)id);
|
||
file->set_folder(dst_folder);
|
||
}
|
||
break;
|
||
case NODE_FILE_FOLDER:
|
||
{
|
||
QString str_id;
|
||
stream >> str_id;
|
||
FileFolder *folder = core()->file_manager()->folder_list()->GetFolderById(str_id.toUtf8().constData());
|
||
if (folder)
|
||
folder->set_owner(dst_folder ? dst_folder : core()->file_manager()->folder_list());
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
} else {
|
||
Folder *dst_folder;
|
||
switch (dst->type()) {
|
||
case NODE_FUNCTION:
|
||
dst_folder = reinterpret_cast<IFunction *>(dst->data())->folder();
|
||
break;
|
||
case NODE_FOLDER:
|
||
dst_folder = reinterpret_cast<Folder *>(dst->data());
|
||
break;
|
||
case NODE_FUNCTIONS:
|
||
dst_folder = NULL;
|
||
break;
|
||
default:
|
||
return false;
|
||
}
|
||
QByteArray encoded = data->data(format);
|
||
QDataStream stream(&encoded, QIODevice::ReadOnly);
|
||
while (!stream.atEnd()) {
|
||
int t;
|
||
stream >> t;
|
||
switch (t) {
|
||
case NODE_FUNCTION:
|
||
{
|
||
QString str_id;
|
||
stream >> str_id;
|
||
FunctionBundle *func = core()->input_file()->function_list()->GetFunctionById(str_id.toUtf8().constData());
|
||
if (func)
|
||
func->set_folder(dst_folder);
|
||
}
|
||
break;
|
||
case NODE_FOLDER:
|
||
{
|
||
QString str_id;
|
||
stream >> str_id;
|
||
Folder *folder = core()->input_file()->folder_list()->GetFolderById(str_id.toUtf8().constData());
|
||
if (folder)
|
||
folder->set_owner(dst_folder ? dst_folder : core()->input_file()->folder_list());
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
QVariant ProjectModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole) {
|
||
if (section == 0)
|
||
return QString::fromUtf8(language[lsProject].c_str());
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
void ProjectModel::addFolder(Folder *folder)
|
||
{
|
||
ProjectNode *node = internalAddFolder(folder);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::updateFolder(Folder *folder)
|
||
{
|
||
ProjectNode *node = internalUpdateFolder(folder);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::removeFolder(Folder *folder)
|
||
{
|
||
if (removeNode(folder))
|
||
emit modified();
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalAddFolder(Folder *folder)
|
||
{
|
||
#ifdef LITE
|
||
return NULL;
|
||
#else
|
||
ProjectNode *nodeFolder = objectToNode(folder->owner());
|
||
if (!nodeFolder)
|
||
nodeFolder = nodeFunctions_;
|
||
ProjectNode *node = new ProjectNode(NULL, NODE_FOLDER, (void *)folder);
|
||
node->setText(QString::fromUtf8(folder->name().c_str()));
|
||
node->setIcon(nodeIcon(node->type()));
|
||
QList<ProjectNode *> folderList = nodeFolder->children();
|
||
int index = folderList.size();
|
||
for (int i = 0; i < folderList.size(); i++) {
|
||
if (folderList[i]->type() != NODE_FOLDER) {
|
||
index = i;
|
||
break;
|
||
}
|
||
}
|
||
beginInsertRows(nodeToIndex(nodeFolder), index, index);
|
||
nodeFolder->insertChild(index, node);
|
||
endInsertRows();
|
||
|
||
setObjectNode(folder, node);
|
||
return node;
|
||
#endif
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalUpdateFolder(Folder *folder)
|
||
{
|
||
#ifdef LITE
|
||
return NULL;
|
||
#else
|
||
ProjectNode *node = objectToNode(folder);
|
||
if (!node)
|
||
return NULL;
|
||
|
||
node->setText(QString::fromUtf8(folder->name().c_str()));
|
||
|
||
ProjectNode *folder_node = folder->owner() ? objectToNode(folder->owner()) : nodeFunctions_;
|
||
ProjectNode *parent_node = node->parent();
|
||
if (folder_node && parent_node && parent_node != folder_node) {
|
||
int index_from = parent_node->children().indexOf(node);
|
||
int index_to = folder_node->childCount();
|
||
for (int i = 0; i < folder_node->childCount(); i++) {
|
||
if (folder_node->child(i)->type() != NODE_FOLDER) {
|
||
index_to = i;
|
||
break;
|
||
}
|
||
}
|
||
beginMoveRows(nodeToIndex(parent_node), index_from, index_from, nodeToIndex(folder_node), index_to);
|
||
parent_node->removeChild(node);
|
||
folder_node->insertChild(index_to, node);
|
||
endMoveRows();
|
||
}
|
||
|
||
return node;
|
||
#endif
|
||
}
|
||
|
||
void ProjectModel::addFunction(IFunction *func)
|
||
{
|
||
ProjectNode *node = internalAddFunction(func);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::updateFunction(IFunction *func)
|
||
{
|
||
ProjectNode *node = internalUpdateFunction(func);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::removeFunction(IFunction *func)
|
||
{
|
||
#ifdef LITE
|
||
FunctionBundle *bundle = core()->input_file()->function_list()->GetFunctionByFunc(func);
|
||
if (!bundle)
|
||
return;
|
||
|
||
removeObject(func);
|
||
|
||
FunctionArch *func_arch = bundle->GetArchByFunction(func);
|
||
if (func_arch)
|
||
delete func_arch;
|
||
if (bundle->count() == 0)
|
||
delete bundle;
|
||
ProjectNode *node = internalUpdateFunction(func);
|
||
if (node)
|
||
updateNode(node);
|
||
#else
|
||
ProjectNode *node = objectToNode(func);
|
||
if (!node)
|
||
return;
|
||
removeObject(func);
|
||
|
||
FunctionBundle *bundle = reinterpret_cast<FunctionBundle *>(node->data());
|
||
FunctionArch *func_arch = bundle->GetArchByFunction(func);
|
||
if (func_arch)
|
||
delete func_arch;
|
||
if (bundle->count() == 0) {
|
||
removeNode(bundle);
|
||
delete bundle;
|
||
}
|
||
#endif
|
||
emit modified();
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalAddFunction(IFunction *func)
|
||
{
|
||
#ifndef LITE
|
||
FunctionBundle *bundle =
|
||
#endif
|
||
core()->input_file()->function_list()->Add(func->owner()->owner(), func);
|
||
#ifndef LITE
|
||
ProjectNode *nodeFolder = objectToNode(func->folder());
|
||
if (!nodeFolder)
|
||
nodeFolder = nodeFunctions_;
|
||
|
||
ProjectNode *node = objectToNode(bundle);
|
||
if (!node) {
|
||
beginInsertRows(nodeToIndex(nodeFolder), nodeFolder->childCount(), nodeFolder->childCount());
|
||
node = new ProjectNode(nodeFolder, NODE_FUNCTION, bundle);
|
||
endInsertRows();
|
||
setObjectNode(bundle, node);
|
||
}
|
||
setObjectNode(func, node);
|
||
|
||
#endif
|
||
return internalUpdateFunction(func);
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalUpdateFunction(IFunction *func)
|
||
{
|
||
#ifdef LITE
|
||
IArchitecture *arch = func->owner()->owner();
|
||
MapFunctionBundle *map_func = core()->input_file()->map_function_list()->GetFunctionByAddress(arch, func->address());
|
||
if (!map_func)
|
||
return NULL;
|
||
|
||
ProjectNode *node = objectToNode(map_func);
|
||
if (!node)
|
||
return NULL;
|
||
|
||
node->setIcon(functionIcon(core()->input_file()->function_list()->GetFunctionByAddress(arch, func->address())));
|
||
#else
|
||
ProjectNode *node = objectToNode(func);
|
||
if (!node)
|
||
return NULL;
|
||
|
||
FunctionBundle *bundle = reinterpret_cast<FunctionBundle *>(node->data());
|
||
std::string func_name = bundle->display_name();
|
||
node->setText(func_name.empty() ? QString::fromUtf8(bundle->display_address().c_str()) : QString::fromUtf8(func_name.c_str()));
|
||
node->setIcon(functionIcon(bundle));
|
||
|
||
ProjectNode *folder_node = bundle->folder() ? objectToNode(bundle->folder()) : nodeFunctions_;
|
||
ProjectNode *parent_node = node->parent();
|
||
if (folder_node && parent_node && parent_node != folder_node) {
|
||
int i = parent_node->children().indexOf(node);
|
||
beginMoveRows(nodeToIndex(parent_node), i, i, nodeToIndex(folder_node), folder_node->childCount());
|
||
parent_node->removeChild(node);
|
||
folder_node->addChild(node);
|
||
endMoveRows();
|
||
}
|
||
#endif
|
||
|
||
return node;
|
||
}
|
||
|
||
void ProjectModel::updateScript()
|
||
{
|
||
#ifndef LITE
|
||
ProjectNode *node = nodeScript_;
|
||
if (!node)
|
||
return;
|
||
|
||
node->setIcon(nodeIcon(node->type(), !core()->script()->need_compile()));
|
||
#endif
|
||
}
|
||
|
||
#ifdef ULTIMATE
|
||
void ProjectModel::addLicense(License *license)
|
||
{
|
||
ProjectNode *node = internalAddLicense(license);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::updateLicense(License *license)
|
||
{
|
||
ProjectNode *node = internalUpdateLicense(license);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::removeLicense(License *license)
|
||
{
|
||
if (removeNode(license))
|
||
emit modified();
|
||
}
|
||
|
||
void ProjectModel::addFileFolder(FileFolder *folder)
|
||
{
|
||
ProjectNode *node = internalAddFileFolder(folder);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::updateFileFolder(FileFolder *folder)
|
||
{
|
||
ProjectNode *node = internalUpdateFileFolder(folder);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::removeFileFolder(FileFolder *folder)
|
||
{
|
||
if (removeNode(folder))
|
||
emit modified();
|
||
}
|
||
|
||
void ProjectModel::addFile(InternalFile *file)
|
||
{
|
||
ProjectNode *node = internalAddFile(file);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::updateFile(InternalFile *file)
|
||
{
|
||
ProjectNode *node = internalUpdateFile(file);
|
||
if (node) {
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
}
|
||
|
||
void ProjectModel::removeFile(InternalFile *file)
|
||
{
|
||
if (removeNode(file))
|
||
emit modified();
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalAddLicense(License *license)
|
||
{
|
||
beginInsertRows(nodeToIndex(nodeLicenses_), nodeLicenses_->childCount(), nodeLicenses_->childCount());
|
||
ProjectNode *node = new ProjectNode(nodeLicenses_, NODE_LICENSE, license);
|
||
endInsertRows();
|
||
|
||
setObjectNode(license, node);
|
||
internalUpdateLicense(license);
|
||
return node;
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalUpdateLicense(License *license)
|
||
{
|
||
ProjectNode *node = objectToNode(license);
|
||
if (!node)
|
||
return NULL;
|
||
|
||
node->setText(QString::fromUtf8(license->customer_name().c_str()));
|
||
node->setIcon(nodeIcon(node->type(), license->blocked()));
|
||
return node;
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalAddFileFolder(FileFolder *folder)
|
||
{
|
||
ProjectNode *nodeFolder = objectToNode(folder->owner());
|
||
if (!nodeFolder)
|
||
nodeFolder = nodeFiles_;
|
||
ProjectNode *node = new ProjectNode(NULL, NODE_FILE_FOLDER, (void *)folder);
|
||
node->setText(QString::fromUtf8(folder->name().c_str()));
|
||
node->setIcon(nodeIcon(node->type()));
|
||
QList<ProjectNode *> folderList = nodeFolder->children();
|
||
int index = folderList.size();
|
||
for (int i = 0; i < folderList.size(); i++) {
|
||
if (folderList[i]->type() != NODE_FILE_FOLDER) {
|
||
index = i;
|
||
break;
|
||
}
|
||
}
|
||
beginInsertRows(nodeToIndex(nodeFolder), index, index);
|
||
nodeFolder->insertChild(index, node);
|
||
endInsertRows();
|
||
|
||
setObjectNode(folder, node);
|
||
return node;
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalUpdateFileFolder(FileFolder *folder)
|
||
{
|
||
ProjectNode *node = objectToNode(folder);
|
||
if (!node)
|
||
return NULL;
|
||
|
||
node->setText(QString::fromUtf8(folder->name().c_str()));
|
||
|
||
ProjectNode *folder_node = folder->owner() ? objectToNode(folder->owner()) : nodeFiles_;
|
||
ProjectNode *parent_node = node->parent();
|
||
if (folder_node && parent_node && parent_node != folder_node) {
|
||
int index_from = parent_node->children().indexOf(node);
|
||
int index_to = folder_node->childCount();
|
||
for (int i = 0; i < folder_node->childCount(); i++) {
|
||
if (folder_node->child(i)->type() != NODE_FILE_FOLDER) {
|
||
index_to = i;
|
||
break;
|
||
}
|
||
}
|
||
beginMoveRows(nodeToIndex(parent_node), index_from, index_from, nodeToIndex(folder_node), index_to);
|
||
parent_node->removeChild(node);
|
||
folder_node->insertChild(index_to, node);
|
||
endMoveRows();
|
||
}
|
||
|
||
return node;
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalAddFile(InternalFile *file)
|
||
{
|
||
if (!nodeFiles_)
|
||
return NULL;
|
||
|
||
ProjectNode *nodeFolder = objectToNode(file->folder());
|
||
if (!nodeFolder)
|
||
nodeFolder = nodeFiles_;
|
||
|
||
beginInsertRows(nodeToIndex(nodeFiles_), nodeFiles_->childCount(), nodeFiles_->childCount());
|
||
ProjectNode *node = new ProjectNode(nodeFolder, NODE_FILE, file);
|
||
endInsertRows();
|
||
|
||
setObjectNode(file, node);
|
||
internalUpdateFile(file);
|
||
return node;
|
||
}
|
||
|
||
ProjectNode *ProjectModel::internalUpdateFile(InternalFile *file)
|
||
{
|
||
ProjectNode *node = objectToNode(file);
|
||
if (!node)
|
||
return NULL;
|
||
|
||
node->setText(QString::fromUtf8(file->name().c_str()));
|
||
node->setIcon(nodeIcon(node->type()));
|
||
ProjectNode *folder_node = file->folder() ? objectToNode(file->folder()) : nodeFiles_;
|
||
ProjectNode *parent_node = node->parent();
|
||
if (folder_node && parent_node && parent_node != folder_node) {
|
||
int i = parent_node->children().indexOf(node);
|
||
beginMoveRows(nodeToIndex(parent_node), i, i, nodeToIndex(folder_node), folder_node->childCount());
|
||
parent_node->removeChild(node);
|
||
folder_node->addChild(node);
|
||
endMoveRows();
|
||
}
|
||
|
||
return node;
|
||
}
|
||
|
||
void ProjectModel::updateFiles()
|
||
{
|
||
ProjectNode *node = nodeFiles_;
|
||
if (!node)
|
||
return;
|
||
|
||
node->setIcon(nodeIcon(node->type(), !core()->file_manager()->need_compile()));
|
||
updateNode(node);
|
||
}
|
||
#endif
|
||
#ifndef LITE
|
||
QRegularExpression FuncRegex("function\\s+[_a-zA-Z]+[_a-zA-Z0-9]*\\s*\\([^\\)]*\\)");
|
||
void ProjectModel::updateScriptBookmarks()
|
||
{
|
||
ProjectNode *parent = nodeScript_;
|
||
if (!parent)
|
||
return;
|
||
|
||
QString script = QString::fromUtf8(core()->script()->text().c_str());
|
||
QRegularExpression multi_space("\\s+");
|
||
int nChild = 0;
|
||
auto it = FuncRegex.globalMatch(script);
|
||
while(it.hasNext()) {
|
||
QString newText = it.next().captured().replace(multi_space, " ");
|
||
|
||
if (nChild >= parent->childCount()) {
|
||
beginInsertRows(nodeToIndex(nodeScript_), nodeScript_->childCount(), nodeScript_->childCount());
|
||
ProjectNode *node = new ProjectNode(nodeScript_, NODE_SCRIPT_BOOKMARK, core()->script());
|
||
node->setText(newText);
|
||
node->setIcon(nodeIcon(node->type()));
|
||
endInsertRows();
|
||
} else {
|
||
ProjectNode *node = parent->child(nChild);
|
||
if(node->text(0).compare(newText)) {
|
||
node->setText(newText);
|
||
updateNode(node);
|
||
}
|
||
}
|
||
nChild++;
|
||
}
|
||
if(nChild != parent->childCount()) {
|
||
beginRemoveRows(nodeToIndex(parent), nChild, parent->childCount() - 1);
|
||
while (nChild != parent->childCount()) {
|
||
ProjectNode *node = parent->child(nChild);
|
||
emit nodeRemoved(node);
|
||
delete node;
|
||
}
|
||
endRemoveRows();
|
||
}
|
||
}
|
||
uptr_t ProjectModel::bookmarkNodeToPos(ProjectNode *node) const
|
||
{
|
||
uptr_t ret = 0;
|
||
int bookIdx = nodeToIndex(node).row();
|
||
QString script = QString::fromUtf8(core()->script()->text().c_str());
|
||
auto it = FuncRegex.globalMatch(script);
|
||
int nChild = 0;
|
||
while (it.hasNext()) {
|
||
auto m = it.next();
|
||
if (nChild == bookIdx)
|
||
return m.capturedStart();
|
||
nChild++;
|
||
}
|
||
return ret;
|
||
}
|
||
#endif
|
||
|
||
void ProjectModel::setCore(Core *core)
|
||
{
|
||
BaseModel::setCore(core);
|
||
|
||
if (!core) {
|
||
beginResetModel();
|
||
nodeFunctions_ = NULL;
|
||
#ifdef ULTIMATE
|
||
nodeLicenses_ = NULL;
|
||
nodeFiles_ = NULL;
|
||
#endif
|
||
#ifndef LITE
|
||
nodeScript_ = NULL;
|
||
#endif
|
||
nodeOptions_ = NULL;
|
||
endResetModel();
|
||
return;
|
||
}
|
||
|
||
size_t i, j;
|
||
|
||
IFile *file = core->input_file();
|
||
if (file) {
|
||
nodeFunctions_ = new ProjectNode(root(), NODE_FUNCTIONS, file->function_list());
|
||
nodeFunctions_->setText(QString::fromUtf8(language[lsFunctionsForProtection].c_str()));
|
||
nodeFunctions_->setIcon(nodeIcon(nodeFunctions_->type()));
|
||
|
||
#ifdef LITE
|
||
setObjectNode(file->map_function_list(), nodeFunctions_);
|
||
createFunctionsTree(nodeFunctions_);
|
||
#else
|
||
setObjectNode(file->folder_list(), nodeFunctions_);
|
||
std::vector<Folder*> folderList = file->folder_list()->GetFolderList();
|
||
for (i = 0; i < folderList.size(); i++) {
|
||
internalAddFolder(folderList[i]);
|
||
}
|
||
#endif
|
||
|
||
for (i = 0; i < file->count(); i++) {
|
||
IArchitecture *arch = file->item(i);
|
||
if (!arch->visible())
|
||
continue;
|
||
|
||
for (j = 0; j < arch->function_list()->count(); j++) {
|
||
internalAddFunction(arch->function_list()->item(j));
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifdef ULTIMATE
|
||
LicensingManager *licensing_manager = core->licensing_manager();
|
||
nodeLicenses_ = new ProjectNode(root(), NODE_LICENSES, licensing_manager);
|
||
nodeLicenses_->setText(QString::fromUtf8(language[lsLicenses].c_str()));
|
||
nodeLicenses_->setIcon(nodeIcon(nodeLicenses_->type()));
|
||
for (i = 0; i < licensing_manager->count(); i++) {
|
||
internalAddLicense(licensing_manager->item(i));
|
||
}
|
||
|
||
if (file && (file->disable_options() & cpVirtualFiles) == 0) {
|
||
FileManager *file_manager = core->file_manager();
|
||
if (file->format_name() == "PE" && file->count() > 1) {
|
||
nodeFiles_ = new ProjectNode(root(), NODE_ASSEMBLIES, file_manager);
|
||
nodeFiles_->setText(QString::fromUtf8(language[lsAssemblies].c_str()));
|
||
}
|
||
else {
|
||
nodeFiles_ = new ProjectNode(root(), NODE_FILES, file_manager);
|
||
nodeFiles_->setText(QString::fromUtf8(language[lsFiles].c_str()));
|
||
}
|
||
nodeFiles_->setIcon(nodeIcon(nodeFiles_->type(), !file_manager->need_compile()));
|
||
setObjectNode(file_manager->folder_list(), nodeFiles_);
|
||
|
||
std::vector<FileFolder*> folderList = file_manager->folder_list()->GetFolderList();
|
||
for (i = 0; i < folderList.size(); i++) {
|
||
internalAddFileFolder(folderList[i]);
|
||
}
|
||
for (i = 0; i < file_manager->count(); i++) {
|
||
internalAddFile(file_manager->item(i));
|
||
}
|
||
}
|
||
#endif
|
||
|
||
if (file) {
|
||
#ifndef LITE
|
||
nodeScript_ = new ProjectNode(root(), NODE_SCRIPT, core->script());
|
||
nodeScript_->setText(QString::fromUtf8(language[lsScript].c_str()));
|
||
nodeScript_->setIcon(nodeIcon(nodeScript_->type(), !core->script()->need_compile()));
|
||
updateScriptBookmarks();
|
||
#endif
|
||
|
||
nodeOptions_ = new ProjectNode(root(), NODE_OPTIONS);
|
||
nodeOptions_->setText(QString::fromUtf8(language[lsOptions].c_str()));
|
||
nodeOptions_->setIcon(nodeIcon(nodeOptions_->type()));
|
||
}
|
||
}
|
||
|
||
struct FunctionBundleListCompareHelper {
|
||
Folder *folder;
|
||
int field;
|
||
FunctionBundleListCompareHelper(Folder *_folder, int _field) : folder(_folder), field(_field) {}
|
||
bool operator () (const FunctionBundle *func1, const FunctionBundle *func2) const
|
||
{
|
||
if (func1->folder() == func2->folder() && func1->folder() == folder) {
|
||
switch (field) {
|
||
case 0:
|
||
return QString::compare(QString::fromUtf8(func1->display_name().c_str()), QString::fromUtf8(func2->display_name().c_str()), Qt::CaseInsensitive) < 0;
|
||
case 1:
|
||
return func1->display_address() < func2->display_address();
|
||
case 2:
|
||
{
|
||
CompilationType ct1 = func1->need_compile() ? func1->compilation_type() : ctNone;
|
||
CompilationType ct2 = func2->need_compile() ? func2->compilation_type() : ctNone;
|
||
return (ct1 == ct2) ? (func1->compilation_options() < func2->compilation_options()) : (ct1 < ct2);
|
||
}
|
||
}
|
||
}
|
||
return func1->folder() < func2->folder();
|
||
}
|
||
};
|
||
|
||
#ifdef ULTIMATE
|
||
struct LicensingManagerCompareHelper {
|
||
int field;
|
||
LicensingManagerCompareHelper(int _field) : field(_field) {}
|
||
bool operator () (const License *license1, const License *license2) const
|
||
{
|
||
switch (field) {
|
||
case 0:
|
||
return QString::compare(QString::fromUtf8(license1->customer_name().c_str()), QString::fromUtf8(license2->customer_name().c_str()), Qt::CaseInsensitive) < 0;
|
||
case 1:
|
||
return QString::compare(QString::fromUtf8(license1->customer_email().c_str()), QString::fromUtf8(license2->customer_email().c_str()), Qt::CaseInsensitive) < 0;
|
||
case 2:
|
||
return license1->date().value() < license2->date().value();
|
||
}
|
||
return false;
|
||
}
|
||
};
|
||
|
||
struct FileManagerCompareHelper {
|
||
FileFolder *folder;
|
||
int field;
|
||
FileManagerCompareHelper(FileFolder *_folder, int _field) : folder(_folder), field(_field) {}
|
||
bool operator () (const InternalFile *file1, const InternalFile *file2) const
|
||
{
|
||
if (file1->folder() == file2->folder() && file1->folder() == folder) {
|
||
switch (field) {
|
||
case 0:
|
||
return QString::compare(QString::fromUtf8(file1->name().c_str()), QString::fromUtf8(file2->name().c_str()), Qt::CaseInsensitive) < 0;
|
||
case 1:
|
||
return QString::compare(QString::fromUtf8(file1->file_name().c_str()), QString::fromUtf8(file2->file_name().c_str()), Qt::CaseInsensitive) < 0;
|
||
}
|
||
}
|
||
return file1->folder() < file2->folder();
|
||
}
|
||
};
|
||
|
||
struct FileFolderCompareHelper {
|
||
bool operator () (const FileFolder *folder1, const FileFolder *folder2) const
|
||
{
|
||
return QString::compare(QString::fromUtf8(folder1->name().c_str()), QString::fromUtf8(folder2->name().c_str()), Qt::CaseInsensitive) < 0;
|
||
}
|
||
};
|
||
#endif
|
||
|
||
struct FolderCompareHelper {
|
||
bool operator () (const Folder *folder1, const Folder *folder2) const
|
||
{
|
||
return QString::compare(QString::fromUtf8(folder1->name().c_str()), QString::fromUtf8(folder2->name().c_str()), Qt::CaseInsensitive) < 0;
|
||
}
|
||
};
|
||
|
||
void ProjectModel::sortNode(ProjectNode *node, int field)
|
||
{
|
||
bool isModified = false;
|
||
QModelIndex parent = nodeToIndex(node);
|
||
QList<ProjectNode*> nodeList = node->children();
|
||
|
||
switch (node->type()) {
|
||
case NODE_FUNCTIONS:
|
||
case NODE_FOLDER:
|
||
{
|
||
IFile *file = core()->input_file();
|
||
Folder *folder = (node->type() == NODE_FUNCTIONS) ? core()->input_file()->folder_list() : reinterpret_cast<Folder *>(node->data());
|
||
|
||
if (field == 0) {
|
||
std::sort(folder->_begin(),folder->_end(), FolderCompareHelper());
|
||
|
||
QList<int> posList;
|
||
for (int i = 0; i < nodeList.size(); i++) {
|
||
ProjectNode *child = nodeList[i];
|
||
if (child->type() != NODE_FOLDER)
|
||
break;
|
||
|
||
int j = (int)folder->IndexOf(reinterpret_cast<Folder *>(child->data()));
|
||
if (j == -1)
|
||
continue;
|
||
|
||
int p = posList.size();
|
||
for (int c = 0; c < posList.size(); c++) {
|
||
if (posList[c] > j) {
|
||
p = c;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (p < i) {
|
||
beginMoveRows(parent, i, i, parent, p);
|
||
node->removeChild(child);
|
||
node->insertChild(p, child);
|
||
endMoveRows();
|
||
isModified = true;
|
||
}
|
||
posList.insert(p, j);
|
||
}
|
||
}
|
||
|
||
if (node->type() == NODE_FUNCTIONS)
|
||
folder = NULL;
|
||
|
||
std::sort(file->function_list()->_begin(), file->function_list()->_end(), FunctionBundleListCompareHelper(folder, field));
|
||
|
||
QList<FunctionBundle *> funcList;
|
||
for (size_t i = 0; i < file->function_list()->count(); i++) {
|
||
FunctionBundle *func = file->function_list()->item(i);
|
||
if (func->folder() == folder)
|
||
funcList.append(func);
|
||
}
|
||
|
||
int k = 0;
|
||
QList<int> posList;
|
||
for (int i = 0; i < nodeList.size(); i++) {
|
||
ProjectNode *child = nodeList[i];
|
||
if (child->type() == NODE_FOLDER) {
|
||
k++;
|
||
continue;
|
||
}
|
||
|
||
int j = funcList.indexOf(reinterpret_cast<FunctionBundle *>(child->data()));
|
||
if (j == -1)
|
||
continue;
|
||
|
||
int p = posList.size();
|
||
for (int c = 0; c < posList.size(); c++) {
|
||
if (posList[c] > j) {
|
||
p = c;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (k + p < i) {
|
||
beginMoveRows(parent, i, i, parent, k + p);
|
||
node->removeChild(child);
|
||
node->insertChild(k + p, child);
|
||
endMoveRows();
|
||
isModified = true;
|
||
}
|
||
posList.insert(p, j);
|
||
}
|
||
}
|
||
break;
|
||
#ifdef ULTIMATE
|
||
case NODE_LICENSES:
|
||
{
|
||
std::sort(core()->licensing_manager()->_begin(), core()->licensing_manager()->_end(), LicensingManagerCompareHelper(field));
|
||
|
||
QList<int> posList;
|
||
for (int i = 0; i < node->childCount(); i++) {
|
||
ProjectNode *child = node->child(i);
|
||
|
||
int j = (int)core()->licensing_manager()->IndexOf(reinterpret_cast<License *>(child->data()));
|
||
if (j == -1)
|
||
continue;
|
||
|
||
int p = posList.size();
|
||
for (int c = 0; c < posList.size(); c++) {
|
||
if (posList[c] > j) {
|
||
p = c;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (p < i) {
|
||
beginMoveRows(parent, i, i, parent, p);
|
||
node->removeChild(child);
|
||
node->insertChild(p, child);
|
||
endMoveRows();
|
||
isModified = true;
|
||
}
|
||
posList.insert(p, j);
|
||
}
|
||
}
|
||
break;
|
||
case NODE_FILES:
|
||
case NODE_FILE_FOLDER:
|
||
case NODE_ASSEMBLIES:
|
||
{
|
||
FileFolder *folder = (node->type() == NODE_FILES || node->type() == NODE_ASSEMBLIES) ? core()->file_manager()->folder_list() : reinterpret_cast<FileFolder *>(node->data());
|
||
|
||
if (field == 0) {
|
||
std::sort(folder->_begin(),folder->_end(), FileFolderCompareHelper());
|
||
|
||
QList<int> posList;
|
||
for (int i = 0; i < node->childCount(); i++) {
|
||
ProjectNode *child = node->child(i);
|
||
if (child->type() != NODE_FILE_FOLDER)
|
||
break;
|
||
|
||
int j = (int)folder->IndexOf(reinterpret_cast<FileFolder *>(child->data()));
|
||
if (j == -1)
|
||
continue;
|
||
|
||
int p = posList.size();
|
||
for (int c = 0; c < posList.size(); c++) {
|
||
if (posList[c] > j) {
|
||
p = c;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (p < i) {
|
||
beginMoveRows(parent, i, i, parent, p);
|
||
node->removeChild(child);
|
||
node->insertChild(p, child);
|
||
endMoveRows();
|
||
isModified = true;
|
||
}
|
||
posList.insert(p, j);
|
||
}
|
||
}
|
||
|
||
if (node->type() == NODE_FILES || node->type() == NODE_ASSEMBLIES)
|
||
folder = NULL;
|
||
|
||
std::sort(core()->file_manager()->_begin(), core()->file_manager()->_end(), FileManagerCompareHelper(folder, field));
|
||
|
||
QList<InternalFile *> fileList;
|
||
for (size_t i = 0; i < core()->file_manager()->count(); i++) {
|
||
InternalFile *file = core()->file_manager()->item(i);
|
||
if (file->folder() == folder)
|
||
fileList.append(file);
|
||
}
|
||
|
||
int k = 0;
|
||
QList<int> posList;
|
||
for (int i = 0; i < node->childCount(); i++) {
|
||
ProjectNode *child = node->child(i);
|
||
if (child->type() == NODE_FILE_FOLDER) {
|
||
k++;
|
||
continue;
|
||
}
|
||
|
||
int j = fileList.indexOf(reinterpret_cast<InternalFile *>(child->data()));
|
||
if (j == -1)
|
||
continue;
|
||
|
||
int p = posList.size();
|
||
for (int c = 0; c < posList.size(); c++) {
|
||
if (posList[c] > j) {
|
||
p = c;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (k + p < i) {
|
||
beginMoveRows(parent, i, i, parent, k + p);
|
||
node->removeChild(child);
|
||
node->insertChild(k + p, child);
|
||
endMoveRows();
|
||
isModified = true;
|
||
}
|
||
posList.insert(p, j);
|
||
}
|
||
}
|
||
break;
|
||
|
||
#endif
|
||
}
|
||
|
||
if (isModified)
|
||
emit modified();
|
||
}
|
||
|
||
/**
|
||
* FunctionsModel
|
||
*/
|
||
|
||
FunctionsModel::FunctionsModel(QObject *parent)
|
||
: BaseModel(parent)
|
||
{
|
||
|
||
}
|
||
|
||
void FunctionsModel::setCore(Core *core)
|
||
{
|
||
beginResetModel();
|
||
BaseModel::setCore(core);
|
||
|
||
if (core)
|
||
createFunctionsTree(root());
|
||
|
||
endResetModel();
|
||
}
|
||
|
||
void FunctionsModel::updateFunction(IFunction *func)
|
||
{
|
||
IArchitecture *arch = func->owner()->owner();
|
||
MapFunctionBundle *map_func = core()->input_file()->map_function_list()->GetFunctionByAddress(arch, func->address());
|
||
if (!map_func)
|
||
return;
|
||
|
||
ProjectNode *node = objectToNode(map_func);
|
||
if (!node)
|
||
return;
|
||
|
||
node->setIcon(functionIcon(core()->input_file()->function_list()->GetFunctionByAddress(arch, func->address())));
|
||
updateNode(node);
|
||
}
|
||
|
||
void FunctionsModel::removeFunction(IFunction *func)
|
||
{
|
||
updateFunction(func);
|
||
}
|
||
|
||
QVariant FunctionsModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole) {
|
||
if (section == 0)
|
||
return QString::fromUtf8(language[lsFunctions].c_str());
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
/**
|
||
* InfoModel
|
||
*/
|
||
|
||
InfoModel::InfoModel(QObject *parent)
|
||
: BaseModel(parent)
|
||
{
|
||
|
||
}
|
||
|
||
void InfoModel::setCore(Core *core)
|
||
{
|
||
BaseModel::setCore(core);
|
||
|
||
if (!core || !core->input_file()) {
|
||
beginResetModel();
|
||
endResetModel();
|
||
return;
|
||
}
|
||
|
||
size_t i, j, k;
|
||
QList<ProjectNode*> nodes;
|
||
for (i = 0; i < core->input_file()->count(); i++) {
|
||
IArchitecture *arch = core->input_file()->item(i);
|
||
if (!arch->visible())
|
||
continue;
|
||
|
||
ProjectNode *node = new ProjectNode(root(), NODE_ARCHITECTURE, arch);
|
||
node->setText(arch->name().c_str());
|
||
node->setIcon(nodeIcon(node->type()));
|
||
nodes.append(node);
|
||
}
|
||
|
||
IArchitecture *default_arch = NULL;
|
||
if (nodes.size() == 1) {
|
||
default_arch = reinterpret_cast<IArchitecture*>(nodes[0]->data());
|
||
delete nodes[0];
|
||
nodes[0] = root();
|
||
}
|
||
|
||
for (int f = 0; f < nodes.size(); f++) {
|
||
ProjectNode *nodeFile = nodes[f];
|
||
IArchitecture *file = (nodeFile->type() == NODE_ROOT) ? default_arch : reinterpret_cast<IArchitecture*>(nodeFile->data());
|
||
assert(file);
|
||
if (file == NULL) continue;
|
||
|
||
if (file->command_list()->count()) {
|
||
ProjectNode *nodeCommands = new ProjectNode(nodeFile, NODE_LOAD_COMMANDS);
|
||
nodeCommands->setText(QString::fromUtf8(language[lsDirectories].c_str()));
|
||
nodeCommands->setIcon(nodeIcon(nodeCommands->type()));
|
||
for (i = 0; i < file->command_list()->count(); i++) {
|
||
ILoadCommand *command = file->command_list()->item(i);
|
||
if (!command->visible())
|
||
continue;
|
||
|
||
ProjectNode *node = new ProjectNode(nodeCommands, NODE_LOAD_COMMAND, command);
|
||
node->setText(QString::fromUtf8(command->name().c_str()));
|
||
node->setIcon(nodeIcon(node->type()));
|
||
setObjectNode(command, node);
|
||
}
|
||
}
|
||
|
||
ProjectNode *nodeSegments = new ProjectNode(nodeFile, NODE_SEGMENTS);
|
||
nodeSegments->setText(QString::fromUtf8(language[lsSegments].c_str()));
|
||
nodeSegments->setIcon(nodeIcon(nodeSegments->type()));
|
||
for (i = 0; i < file->segment_list()->count(); i++) {
|
||
ISection *segment = file->segment_list()->item(i);
|
||
|
||
ProjectNode *node = new ProjectNode(nodeSegments, NODE_SEGMENT, segment);
|
||
node->setText(QString::fromUtf8(segment->name().c_str()));
|
||
bool has_children = false;
|
||
for (j = 0; j < file->section_list()->count(); j++) {
|
||
if (file->section_list()->item(j)->parent() == segment) {
|
||
has_children = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
node->setIcon(nodeIcon(has_children ? NODE_FOLDER : node->type(), segment->excluded_from_packing() || segment->excluded_from_memory_protection()));
|
||
setObjectNode(segment, node);
|
||
}
|
||
|
||
for (i = 0; i < file->section_list()->count(); i++) {
|
||
ISection *section = file->section_list()->item(i);
|
||
j = file->segment_list()->IndexOf(section->parent());
|
||
if (j == NOT_ID)
|
||
continue;
|
||
|
||
ProjectNode *node = new ProjectNode(nodeSegments->child((int)j), NODE_SECTION, section);
|
||
node->setText(QString::fromUtf8(section->name().c_str()));
|
||
node->setIcon(nodeIcon(node->type()));
|
||
}
|
||
|
||
if (file->import_list()->count()) {
|
||
ProjectNode *nodeImports = new ProjectNode(nodeFile, NODE_IMPORTS, file->import_list());
|
||
nodeImports->setText(QString::fromUtf8(language[lsImports].c_str()));
|
||
nodeImports->setIcon(nodeIcon(nodeImports->type()));
|
||
for (i = 0; i < file->import_list()->count(); i++) {
|
||
IImport *import = file->import_list()->item(i);
|
||
|
||
ProjectNode *nodeImport = new ProjectNode(nodeImports, NODE_IMPORT, import);
|
||
nodeImport->setText(QString::fromUtf8(import->name().c_str()));
|
||
nodeImport->setIcon(nodeIcon(nodeImport->type(), import->excluded_from_import_protection()));
|
||
setObjectNode(import, nodeImport);
|
||
|
||
createFunctionsTree(nodeImport);
|
||
|
||
if (import->name().empty()) {
|
||
QList<ProjectNode *> nodeList = nodeImport->children();
|
||
for (int k = 0; k < nodeList.count(); k++) {
|
||
ProjectNode *child = nodeList[k];
|
||
nodeImport->removeChild(child);
|
||
nodeImports->addChild(child);
|
||
}
|
||
delete nodeImport;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (file->export_list()->count()) {
|
||
ProjectNode *nodeExports = new ProjectNode(nodeFile, NODE_EXPORTS, file->export_list());
|
||
nodeExports->setText(QString::fromUtf8(language[lsExports].c_str()));
|
||
nodeExports->setIcon(nodeIcon(nodeExports->type()));
|
||
|
||
createFunctionsTree(nodeExports);
|
||
}
|
||
|
||
if (file->resource_list() && file->resource_list()->count()) {
|
||
ProjectNode *nodeResources = new ProjectNode(nodeFile, NODE_RESOURCES, file->resource_list());
|
||
nodeResources->setText(QString::fromUtf8(language[lsResources].c_str()));
|
||
nodeResources->setIcon(nodeIcon(nodeResources->type()));
|
||
std::vector<IResource *> resourceList;
|
||
for (i = 0; i < file->resource_list()->count(); i++) {
|
||
resourceList.push_back(file->resource_list()->item(i));
|
||
}
|
||
for (k = 0; k < resourceList.size(); k++) {
|
||
IResource *resource = resourceList[k];
|
||
for (j = 0; j < resource->count(); j++) {
|
||
resourceList.push_back(resource->item(j));
|
||
}
|
||
}
|
||
for (k = 0; k < resourceList.size(); k++) {
|
||
IResource *resource = resourceList[k];
|
||
|
||
ProjectNode *nodeParent = objectToNode(resource->owner());
|
||
if (!nodeParent)
|
||
nodeParent = nodeResources;
|
||
ProjectNode *node = new ProjectNode(nodeParent, resource->is_directory() ? NODE_RESOURCE_FOLDER : NODE_RESOURCE, resource);
|
||
node->setText(QString::fromUtf8(resource->name().c_str()));
|
||
node->setIcon(nodeIcon(node->type(), node->type() == NODE_RESOURCE && resource->excluded_from_packing()));
|
||
setObjectNode(resource, node);
|
||
}
|
||
}
|
||
|
||
ProjectNode *nodeCalc = new ProjectNode(nodeFile, NODE_CALC, file);
|
||
nodeCalc->setText(QString::fromUtf8(language[lsCalculator].c_str()));
|
||
nodeCalc->setIcon(nodeIcon(nodeCalc->type()));
|
||
|
||
ProjectNode *nodeDump = new ProjectNode(nodeFile, NODE_DUMP, file);
|
||
nodeDump->setText(QString::fromUtf8(language[lsDump].c_str()));
|
||
nodeDump->setIcon(nodeIcon(nodeDump->type()));
|
||
setObjectNode(file, nodeDump);
|
||
}
|
||
}
|
||
|
||
void InfoModel::updateResource(IResource *resource)
|
||
{
|
||
ProjectNode *node = objectToNode(resource);
|
||
if (!node)
|
||
return;
|
||
|
||
node->setIcon(nodeIcon(node->type(), resource->excluded_from_packing()));
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
|
||
void InfoModel::updateSegment(ISection *segment)
|
||
{
|
||
ProjectNode *node = objectToNode(segment);
|
||
if (!node)
|
||
return;
|
||
|
||
node->setIcon(nodeIcon(node->childCount() ? NODE_FOLDER : node->type(), segment->excluded_from_packing() || segment->excluded_from_memory_protection()));
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
|
||
void InfoModel::updateImport(IImport *import)
|
||
{
|
||
ProjectNode *node = objectToNode(import);
|
||
if (!node)
|
||
return;
|
||
|
||
node->setIcon(nodeIcon(node->type(), import->excluded_from_import_protection()));
|
||
updateNode(node);
|
||
emit modified();
|
||
}
|
||
|
||
QVariant InfoModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole) {
|
||
if (section == 0)
|
||
return QString::fromUtf8(language[lsDetails].c_str());
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
/**
|
||
* SearchModel
|
||
*/
|
||
|
||
SearchModel::SearchModel(QObject *parent)
|
||
: QAbstractItemModel(parent)
|
||
{
|
||
|
||
}
|
||
|
||
void SearchModel::clear()
|
||
{
|
||
if (items_.count())
|
||
removeRows(0, items_.count());
|
||
}
|
||
|
||
void SearchModel::search(ProjectNode *directory, const QString &text, bool protectedFunctionsOnly)
|
||
{
|
||
beginResetModel();
|
||
QList<ProjectNode *> list;
|
||
QRegExp filter(text, Qt::CaseInsensitive, QRegExp::Wildcard);
|
||
|
||
items_.clear();
|
||
list.append(directory);
|
||
for (int i = 0; i < list.count(); i++) {
|
||
ProjectNode *node = list[i];
|
||
for (int j = 0; j < node->childCount(); j++) {
|
||
list.insert(i + 1 + j, node->child(j));
|
||
}
|
||
|
||
if (node->properties())
|
||
list.insert(i + 1, node->properties());
|
||
|
||
if (node->parent() && node->contains(filter)) {
|
||
if (protectedFunctionsOnly) {
|
||
switch (node->type()) {
|
||
case NODE_MAP_FUNCTION:
|
||
{
|
||
MapFunctionBundle *map = reinterpret_cast<MapFunctionBundle*>(node->data());
|
||
FunctionBundle *func = map->owner()->owner()->function_list()->GetFunctionByName(map->name());
|
||
if (!func || !func->need_compile())
|
||
continue;
|
||
}
|
||
break;
|
||
default:
|
||
continue;
|
||
}
|
||
}
|
||
items_.append(node);
|
||
}
|
||
}
|
||
|
||
endResetModel();
|
||
}
|
||
|
||
QModelIndex SearchModel::index(int row, int column, const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid() && parent.column() != 0)
|
||
return QModelIndex();
|
||
|
||
ProjectNode *node = items_.value(row);
|
||
if (!node)
|
||
return QModelIndex();
|
||
|
||
return createIndex(row, column, node);
|
||
}
|
||
|
||
QModelIndex SearchModel::parent(const QModelIndex & /*index*/) const
|
||
{
|
||
return QModelIndex();
|
||
}
|
||
|
||
int SearchModel::rowCount(const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid())
|
||
return 0;
|
||
|
||
return items_.size();
|
||
}
|
||
|
||
int SearchModel::columnCount(const QModelIndex & /*parent*/) const
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
ProjectNode *SearchModel::indexToNode(const QModelIndex &index) const
|
||
{
|
||
if (index.isValid())
|
||
return static_cast<ProjectNode *>(index.internalPointer());
|
||
return NULL;
|
||
}
|
||
|
||
QVariant SearchModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if (!index.isValid())
|
||
return QVariant();
|
||
|
||
ProjectNode *node = indexToNode(index);
|
||
assert(node);
|
||
if (node != NULL) {
|
||
switch (role) {
|
||
case Qt::DisplayRole:
|
||
return node->text(index.column());
|
||
case Qt::DecorationRole:
|
||
if (index.column() == 0)
|
||
return node->icon();
|
||
break;
|
||
case Qt::ToolTipRole:
|
||
{
|
||
QString text = node->path();
|
||
if (!text.isEmpty())
|
||
text += " > " + node->text(index.column());
|
||
return text;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
QVariant SearchModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole)
|
||
return QString::fromUtf8(language[lsSearchResult].c_str());
|
||
return QVariant();
|
||
}
|
||
|
||
QModelIndex SearchModel::nodeToIndex(ProjectNode *node) const
|
||
{
|
||
int i = items_.indexOf(node);
|
||
if (i == -1)
|
||
return QModelIndex();
|
||
|
||
return createIndex(i, 0, node);
|
||
}
|
||
|
||
void SearchModel::updateNode(ProjectNode *node)
|
||
{
|
||
int i = items_.indexOf(node);
|
||
if (i == -1)
|
||
return;
|
||
|
||
QModelIndex index = createIndex(i, 0, node);
|
||
dataChanged(index, index);
|
||
}
|
||
|
||
bool SearchModel::removeRows(int position, int rows, const QModelIndex &parent)
|
||
{
|
||
bool res;
|
||
|
||
beginRemoveRows(parent, position, position + rows - 1);
|
||
if (position < 0 || position + rows > items_.size()) {
|
||
res = false;
|
||
} else {
|
||
for (int row = position; row < rows; ++row)
|
||
items_.removeAt(position);
|
||
res = true;
|
||
}
|
||
endRemoveRows();
|
||
|
||
return res;
|
||
}
|
||
|
||
void SearchModel::removeNode(ProjectNode *node)
|
||
{
|
||
int i = items_.indexOf(node);
|
||
if (i == -1)
|
||
return;
|
||
|
||
removeRows(i, 1);
|
||
}
|
||
|
||
/**
|
||
* DirectoryModel
|
||
*/
|
||
|
||
DirectoryModel::DirectoryModel(QObject *parent)
|
||
: QAbstractItemModel(parent), directory_(NULL)
|
||
{
|
||
|
||
}
|
||
|
||
Qt::ItemFlags DirectoryModel::flags(const QModelIndex &index) const
|
||
{
|
||
Qt::ItemFlags res = QAbstractItemModel::flags(index);
|
||
if (res & Qt::ItemIsSelectable) {
|
||
ProjectNode *node = indexToNode(index);
|
||
if (node) {
|
||
if (node->type() == NODE_FILE_FOLDER || node->type() == NODE_FOLDER || node->type() == NODE_FILE || node->type() == NODE_LICENSE)
|
||
res |= Qt::ItemIsEditable;
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
void DirectoryModel::setDirectory(ProjectNode *directory)
|
||
{
|
||
beginResetModel();
|
||
directory_ = directory;
|
||
if (directory_) {
|
||
items_ = directory->children();
|
||
} else {
|
||
items_.clear();
|
||
}
|
||
|
||
endResetModel();
|
||
}
|
||
|
||
QModelIndex DirectoryModel::index(int row, int column, const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid() && parent.column() != 0)
|
||
return QModelIndex();
|
||
|
||
ProjectNode *node = items_.value(row);
|
||
if (!node)
|
||
return QModelIndex();
|
||
|
||
return createIndex(row, column, node);
|
||
}
|
||
|
||
QModelIndex DirectoryModel::parent(const QModelIndex & /*index*/) const
|
||
{
|
||
return QModelIndex();
|
||
}
|
||
|
||
int DirectoryModel::rowCount(const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid())
|
||
return 0;
|
||
|
||
return items_.size();
|
||
}
|
||
|
||
QStringList headerLabels(NodeType type)
|
||
{
|
||
QStringList res;
|
||
switch (type) {
|
||
case NODE_FUNCTIONS:
|
||
case NODE_FOLDER:
|
||
case NODE_MAP_FOLDER:
|
||
res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsAddress].c_str()) << QString::fromUtf8(language[lsProtection].c_str());
|
||
break;
|
||
case NODE_RESOURCES:
|
||
case NODE_RESOURCE_FOLDER:
|
||
case NODE_LOAD_COMMANDS:
|
||
res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsAddress].c_str()) << QString::fromUtf8(language[lsSize].c_str());
|
||
break;
|
||
case NODE_SEGMENTS:
|
||
case NODE_SEGMENT:
|
||
res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsAddress].c_str()) << QString::fromUtf8(language[lsSize].c_str()) << QString::fromUtf8(language[lsRawAddress].c_str()) << QString::fromUtf8(language[lsRawSize].c_str()) << QString::fromUtf8(language[lsFlags].c_str());
|
||
break;
|
||
case NODE_IMPORT:
|
||
case NODE_IMPORT_FOLDER:
|
||
case NODE_EXPORTS:
|
||
case NODE_EXPORT_FOLDER:
|
||
res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsAddress].c_str());
|
||
break;
|
||
case NODE_LICENSES:
|
||
res << QString::fromUtf8(language[lsCustomerName].c_str()) << QString::fromUtf8(language[lsEmail].c_str()) << QString::fromUtf8(language[lsDate].c_str());
|
||
break;
|
||
case NODE_FILES:
|
||
case NODE_FILE_FOLDER:
|
||
case NODE_ASSEMBLIES:
|
||
res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsFileName].c_str());
|
||
break;
|
||
default:
|
||
res << QString::fromUtf8(language[lsName].c_str());
|
||
break;
|
||
}
|
||
return res;
|
||
};
|
||
|
||
int DirectoryModel::columnCount(const QModelIndex & /*parent*/) const
|
||
{
|
||
if (!directory_)
|
||
return 0;
|
||
|
||
return headerLabels(directory_->type()).size();
|
||
}
|
||
|
||
ProjectNode *DirectoryModel::indexToNode(const QModelIndex &index) const
|
||
{
|
||
if (index.isValid())
|
||
return static_cast<ProjectNode *>(index.internalPointer());
|
||
return NULL;
|
||
}
|
||
|
||
QVariant DirectoryModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if (!index.isValid())
|
||
return QVariant();
|
||
|
||
ProjectNode *node = indexToNode(index);
|
||
if (node != NULL) {
|
||
if (role == Qt::DisplayRole) {
|
||
return node->text(index.column());
|
||
} else if (role == Qt::DecorationRole) {
|
||
if (index.column() == 0)
|
||
return node->icon();
|
||
}
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
QVariant DirectoryModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (!directory_)
|
||
return QVariant();
|
||
|
||
if (role == Qt::DisplayRole) {
|
||
return headerLabels(directory_->type()).value(section);
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
QModelIndex DirectoryModel::nodeToIndex(ProjectNode *node) const
|
||
{
|
||
int i = items_.indexOf(node);
|
||
if (i == -1)
|
||
return QModelIndex();
|
||
|
||
return createIndex(i, 0, node);
|
||
}
|
||
|
||
void DirectoryModel::updateNode(ProjectNode *node)
|
||
{
|
||
int i = items_.indexOf(node);
|
||
if (i == -1)
|
||
return;
|
||
|
||
QModelIndex index = createIndex(i, 0, node);
|
||
dataChanged(index, index);
|
||
}
|
||
|
||
bool DirectoryModel::removeRows(int position, int rows, const QModelIndex &parent)
|
||
{
|
||
bool res;
|
||
|
||
beginRemoveRows(parent, position, position + rows - 1);
|
||
if (position < 0 || position + rows > items_.size()) {
|
||
res = false;
|
||
} else {
|
||
for (int row = 0; row < rows; ++row)
|
||
items_.removeAt(position);
|
||
res = true;
|
||
}
|
||
endRemoveRows();
|
||
|
||
return res;
|
||
}
|
||
|
||
void DirectoryModel::removeNode(ProjectNode *node)
|
||
{
|
||
ProjectNode *parent = directory_;
|
||
while (parent) {
|
||
if (parent == node) {
|
||
setDirectory(NULL);
|
||
return;
|
||
}
|
||
parent = parent->parent();
|
||
}
|
||
|
||
int i = items_.indexOf(node);
|
||
if (i == -1)
|
||
return;
|
||
|
||
removeRows(i, 1);
|
||
}
|
||
|
||
/**
|
||
* MapFunctionBundleListModel
|
||
*/
|
||
|
||
MapFunctionBundleListModel::MapFunctionBundleListModel(IFile &file, bool codeOnly, QObject *parent)
|
||
: QAbstractItemModel(parent)
|
||
{
|
||
MapFunctionBundleList *map_function_list = file.map_function_list();
|
||
for (size_t i = 0; i < map_function_list->count(); i++) {
|
||
MapFunctionBundle *func = map_function_list->item(i);
|
||
switch (func->type()) {
|
||
case otCode:
|
||
case otExport:
|
||
case otMarker:
|
||
case otAPIMarker:
|
||
case otString:
|
||
break;
|
||
case otUnknown:
|
||
continue;
|
||
default:
|
||
if (codeOnly)
|
||
continue;
|
||
break;
|
||
}
|
||
|
||
mapFunctionList_.append(func);
|
||
}
|
||
|
||
items_ = mapFunctionList_;
|
||
}
|
||
|
||
int MapFunctionBundleListModel::rowCount(const QModelIndex &parent) const
|
||
{
|
||
if (!parent.isValid())
|
||
return items_.size();
|
||
|
||
return 0;
|
||
}
|
||
|
||
int MapFunctionBundleListModel::columnCount(const QModelIndex &parent) const
|
||
{
|
||
Q_UNUSED(parent);
|
||
return 2;
|
||
}
|
||
|
||
QModelIndex MapFunctionBundleListModel::index(int row, int column, const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid() && parent.column() != 0)
|
||
return QModelIndex();
|
||
|
||
MapFunctionBundle *bundle = items_.value(row);
|
||
if (!bundle)
|
||
return QModelIndex();
|
||
|
||
return createIndex(row, column, bundle);
|
||
}
|
||
|
||
QModelIndex MapFunctionBundleListModel::parent(const QModelIndex & /*index*/) const
|
||
{
|
||
return QModelIndex();
|
||
}
|
||
|
||
QVariant MapFunctionBundleListModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if (!index.isValid())
|
||
return QVariant();
|
||
|
||
MapFunctionBundle *func = items_.at(index.row());
|
||
|
||
if (role == Qt::DisplayRole) {
|
||
if (index.column() == 0) {
|
||
return QString::fromUtf8(func->display_name().c_str());
|
||
} else if (index.column() == 1) {
|
||
return QString::fromLatin1(func->display_address().c_str());
|
||
}
|
||
} else if (role == Qt::DecorationRole) {
|
||
if (index.column() == 0) {
|
||
switch (func->type()) {
|
||
case otImport:
|
||
return nodeIcon(NODE_IMPORT_FUNCTION);
|
||
default:
|
||
return functionIcon(func->owner()->owner()->function_list()->GetFunctionByName(func->name()));
|
||
}
|
||
}
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
QVariant MapFunctionBundleListModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role != Qt::DisplayRole)
|
||
return QVariant();
|
||
|
||
switch (section) {
|
||
case 0:
|
||
return QString::fromUtf8(language[lsName].c_str());
|
||
case 1:
|
||
return QString::fromUtf8(language[lsAddress].c_str());
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
void MapFunctionBundleListModel::search(const QString &text)
|
||
{
|
||
beginResetModel();
|
||
if (text.isEmpty()) {
|
||
items_ = mapFunctionList_;
|
||
} else {
|
||
items_.clear();
|
||
QRegExp filter(text, Qt::CaseInsensitive, QRegExp::Wildcard);
|
||
|
||
for (int i = 0; i < mapFunctionList_.size(); i++) {
|
||
MapFunctionBundle *func = mapFunctionList_[i];
|
||
QString name = QString::fromUtf8(func->name().c_str());
|
||
if (name.contains(filter))
|
||
items_.append(func);
|
||
}
|
||
}
|
||
|
||
endResetModel();
|
||
}
|
||
|
||
struct MapFunctionBundleListCompareHelper {
|
||
int column;
|
||
MapFunctionBundleListCompareHelper(int _column) : column(_column) {}
|
||
bool operator () (const MapFunctionBundle *func1, const MapFunctionBundle *func2) const
|
||
{
|
||
switch (column) {
|
||
case 0:
|
||
return QString::fromUtf8(func1->display_name().c_str()).compare(QString::fromUtf8(func2->display_name().c_str()), Qt::CaseInsensitive) < 0;
|
||
case 1:
|
||
return func1->display_address() < func2->display_address();
|
||
}
|
||
return false;
|
||
}
|
||
};
|
||
|
||
void MapFunctionBundleListModel::sort(int column, Qt::SortOrder order)
|
||
{
|
||
beginResetModel();
|
||
qSort(mapFunctionList_.begin(), mapFunctionList_.end(), MapFunctionBundleListCompareHelper(column));
|
||
if (items_.size() == mapFunctionList_.size())
|
||
items_ = mapFunctionList_;
|
||
else
|
||
qSort(items_.begin(), items_.end(), MapFunctionBundleListCompareHelper(column));
|
||
endResetModel();
|
||
}
|
||
|
||
/**
|
||
* MapFunctionListModel
|
||
*/
|
||
|
||
MapFunctionListModel::MapFunctionListModel(IArchitecture &file, bool codeOnly, QObject *parent)
|
||
: QAbstractItemModel(parent)
|
||
{
|
||
MapFunctionList *map_function_list = file.map_function_list();
|
||
for (size_t i = 0; i < map_function_list->count(); i++) {
|
||
MapFunction *func = map_function_list->item(i);
|
||
switch (func->type()) {
|
||
case otCode:
|
||
case otExport:
|
||
case otMarker:
|
||
case otAPIMarker:
|
||
case otString:
|
||
break;
|
||
case otUnknown:
|
||
continue;
|
||
default:
|
||
if (codeOnly)
|
||
continue;
|
||
break;
|
||
}
|
||
|
||
mapFunctionList_.append(func);
|
||
}
|
||
|
||
items_ = mapFunctionList_;
|
||
}
|
||
|
||
int MapFunctionListModel::rowCount(const QModelIndex &parent) const
|
||
{
|
||
if (!parent.isValid())
|
||
return items_.size();
|
||
|
||
return 0;
|
||
}
|
||
|
||
int MapFunctionListModel::columnCount(const QModelIndex &parent) const
|
||
{
|
||
Q_UNUSED(parent);
|
||
return 2;
|
||
}
|
||
|
||
QModelIndex MapFunctionListModel::index(int row, int column, const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid() && parent.column() != 0)
|
||
return QModelIndex();
|
||
|
||
MapFunction *func = items_.value(row);
|
||
if (!func)
|
||
return QModelIndex();
|
||
|
||
return createIndex(row, column, func);
|
||
}
|
||
|
||
QModelIndex MapFunctionListModel::parent(const QModelIndex & /*index*/) const
|
||
{
|
||
return QModelIndex();
|
||
}
|
||
|
||
QVariant MapFunctionListModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if (!index.isValid())
|
||
return QVariant();
|
||
|
||
MapFunction *func = items_.at(index.row());
|
||
|
||
if (role == Qt::DisplayRole) {
|
||
if (index.column() == 0) {
|
||
return QString::fromUtf8(func->display_name().c_str());
|
||
} else if (index.column() == 1) {
|
||
return QString::fromLatin1(func->display_address("").c_str());
|
||
}
|
||
} else if (role == Qt::DecorationRole) {
|
||
if (index.column() == 0) {
|
||
switch (func->type()) {
|
||
case otImport:
|
||
return nodeIcon(NODE_IMPORT_FUNCTION);
|
||
default:
|
||
return functionIcon(func->owner()->owner()->function_list()->GetFunctionByAddress(func->address()));
|
||
}
|
||
}
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
QVariant MapFunctionListModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role != Qt::DisplayRole)
|
||
return QVariant();
|
||
|
||
switch (section) {
|
||
case 0:
|
||
return QString::fromUtf8(language[lsName].c_str());
|
||
case 1:
|
||
return QString::fromUtf8(language[lsAddress].c_str());
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
void MapFunctionListModel::search(const QString &text)
|
||
{
|
||
beginResetModel();
|
||
if (text.isEmpty()) {
|
||
items_ = mapFunctionList_;
|
||
} else {
|
||
items_.clear();
|
||
QRegExp filter(text, Qt::CaseInsensitive, QRegExp::Wildcard);
|
||
|
||
for (int i = 0; i < mapFunctionList_.size(); i++) {
|
||
MapFunction *func = mapFunctionList_[i];
|
||
QString name = QString::fromUtf8(func->name().c_str());
|
||
if (name.contains(filter))
|
||
items_.append(func);
|
||
}
|
||
}
|
||
|
||
endResetModel();
|
||
}
|
||
|
||
struct MapFunctionListCompareHelper {
|
||
int column;
|
||
MapFunctionListCompareHelper(int _column) : column(_column) {}
|
||
bool operator () (const MapFunction *func1, const MapFunction *func2) const
|
||
{
|
||
switch (column) {
|
||
case 0:
|
||
return QString::fromUtf8(func1->display_name().c_str()).compare(QString::fromUtf8(func2->display_name().c_str()), Qt::CaseInsensitive) < 0;
|
||
case 1:
|
||
return func1->display_address("") < func2->display_address("");
|
||
}
|
||
return false;
|
||
}
|
||
};
|
||
|
||
void MapFunctionListModel::sort(int column, Qt::SortOrder order)
|
||
{
|
||
beginResetModel();
|
||
qSort(mapFunctionList_.begin(), mapFunctionList_.end(), MapFunctionListCompareHelper(column));
|
||
if (items_.size() == mapFunctionList_.size())
|
||
items_ = mapFunctionList_;
|
||
else
|
||
qSort(items_.begin(), items_.end(), MapFunctionListCompareHelper(column));
|
||
endResetModel();
|
||
}
|
||
|
||
/**
|
||
* WatermarksModel
|
||
*/
|
||
|
||
WatermarksModel::WatermarksModel(QObject *parent)
|
||
: BaseModel(parent)
|
||
{
|
||
|
||
}
|
||
|
||
QVariant WatermarksModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole) {
|
||
if (section == 0)
|
||
return QString::fromUtf8(language[lsName].c_str());
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
Qt::ItemFlags WatermarksModel::flags(const QModelIndex &index) const
|
||
{
|
||
Qt::ItemFlags res = QAbstractItemModel::flags(index);
|
||
if (res & Qt::ItemIsSelectable) {
|
||
ProjectNode *node = indexToNode(index);
|
||
if (node) {
|
||
if (node->type() == NODE_WATERMARK)
|
||
res |= Qt::ItemIsEditable;
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
ProjectNode *WatermarksModel::internalAddWatermark(Watermark *watermark)
|
||
{
|
||
beginInsertRows(nodeToIndex(NULL), root()->childCount(), root()->childCount());
|
||
ProjectNode *node = new ProjectNode(root(), NODE_WATERMARK, (void *)watermark);
|
||
endInsertRows();
|
||
|
||
setObjectNode(watermark, node);
|
||
internalUpdateWatermark(watermark);
|
||
return node;
|
||
}
|
||
|
||
ProjectNode *WatermarksModel::internalUpdateWatermark(Watermark *watermark)
|
||
{
|
||
ProjectNode *node = objectToNode(watermark);
|
||
if (!node)
|
||
return NULL;
|
||
|
||
node->setText(QString::fromUtf8(watermark->name().c_str()));
|
||
node->setIcon(nodeIcon(node->type(), !watermark->enabled()));
|
||
return node;
|
||
}
|
||
|
||
void WatermarksModel::setCore(Core *core)
|
||
{
|
||
beginResetModel();
|
||
BaseModel::setCore(core);
|
||
|
||
if (core) {
|
||
WatermarkManager *manager = core->watermark_manager();
|
||
for (size_t i = 0; i < manager->count(); i++) {
|
||
internalAddWatermark(manager->item(i));
|
||
}
|
||
}
|
||
endResetModel();
|
||
}
|
||
|
||
void WatermarksModel::addWatermark(Watermark *watermark)
|
||
{
|
||
updateNode(internalAddWatermark(watermark));
|
||
}
|
||
|
||
void WatermarksModel::updateWatermark(Watermark *watermark)
|
||
{
|
||
updateNode(internalUpdateWatermark(watermark));
|
||
}
|
||
|
||
void WatermarksModel::removeWatermark(Watermark *watermark)
|
||
{
|
||
removeNode(watermark);
|
||
}
|
||
|
||
QModelIndex WatermarksModel::indexByName(const QString &watermarkName) const
|
||
{
|
||
for (int i = 0; i < root()->childCount(); i++) {
|
||
ProjectNode *node = root()->child(i);
|
||
if (node->text() == watermarkName)
|
||
return nodeToIndex(node);
|
||
}
|
||
|
||
return QModelIndex();
|
||
}
|
||
|
||
WatermarkManager * WatermarksModel::manager() const
|
||
{
|
||
return core() ? core()->watermark_manager() : NULL;
|
||
}
|
||
|
||
/**
|
||
* WatermarkScanModel
|
||
*/
|
||
|
||
WatermarkScanModel::WatermarkScanModel(QObject *parent)
|
||
: QAbstractItemModel(parent)
|
||
{
|
||
|
||
}
|
||
|
||
QModelIndex WatermarkScanModel::index(int row, int column, const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid() && parent.column() != 0)
|
||
return QModelIndex();
|
||
|
||
Watermark *watermark = items_.keys().value(row);
|
||
if (!watermark)
|
||
return QModelIndex();
|
||
|
||
return createIndex(row, column, watermark);
|
||
}
|
||
|
||
QModelIndex WatermarkScanModel::parent(const QModelIndex & /*index*/) const
|
||
{
|
||
return QModelIndex();
|
||
}
|
||
|
||
int WatermarkScanModel::rowCount(const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid())
|
||
return 0;
|
||
|
||
return items_.size();
|
||
}
|
||
|
||
int WatermarkScanModel::columnCount(const QModelIndex & /*parent*/) const
|
||
{
|
||
return 2;
|
||
}
|
||
|
||
Watermark *WatermarkScanModel::indexToWatermark(const QModelIndex &index) const
|
||
{
|
||
if (index.isValid())
|
||
return static_cast<Watermark *>(index.internalPointer());
|
||
return NULL;
|
||
}
|
||
|
||
QVariant WatermarkScanModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if (!index.isValid())
|
||
return QVariant();
|
||
|
||
Watermark *watermark = indexToWatermark(index);
|
||
assert(watermark);
|
||
if (watermark != NULL ) {
|
||
if (role == Qt::DisplayRole) {
|
||
if (index.column() == 0) {
|
||
return QString::fromUtf8(watermark->name().c_str());
|
||
} else if (index.column() == 1) {
|
||
return QString::number(items_[watermark]);
|
||
}
|
||
} else if (role == Qt::DecorationRole) {
|
||
if (index.column() == 0)
|
||
return watermark->enabled() ? QIcon(":/images/item_watermark.png") : QIcon(":/images/item_watermark_black.png");
|
||
}
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
QVariant WatermarkScanModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole) {
|
||
if (section == 0) {
|
||
return QString::fromUtf8(language[lsName].c_str());
|
||
} else if (section == 1) {
|
||
return QString::fromUtf8(language[lsCount].c_str());
|
||
}
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
void WatermarkScanModel::setWatermarkData(std::map<Watermark *, size_t> data)
|
||
{
|
||
beginResetModel();
|
||
items_.clear();
|
||
for (std::map<Watermark *, size_t>::const_iterator it = data.begin(); it != data.end(); it++) {
|
||
items_[it->first] = it->second;
|
||
}
|
||
|
||
endResetModel();
|
||
}
|
||
|
||
void WatermarkScanModel::removeWatermark(Watermark *watermark)
|
||
{
|
||
int position = items_.keys().indexOf(watermark);
|
||
if (position == -1)
|
||
return;
|
||
|
||
beginRemoveRows(QModelIndex(), position, position);
|
||
items_.remove(watermark);
|
||
endRemoveRows();
|
||
}
|
||
|
||
void WatermarkScanModel::clear()
|
||
{
|
||
if (items_.count())
|
||
removeRows(0, items_.count());
|
||
}
|
||
|
||
/**
|
||
* TemplatesModel
|
||
*/
|
||
|
||
TemplatesModel::TemplatesModel(QObject *parent)
|
||
: BaseModel(parent)
|
||
{
|
||
|
||
}
|
||
|
||
QVariant TemplatesModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole) {
|
||
if (section == 0)
|
||
return QString::fromUtf8(language[lsName].c_str());
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
Qt::ItemFlags TemplatesModel::flags(const QModelIndex &index) const
|
||
{
|
||
Qt::ItemFlags res = QAbstractItemModel::flags(index);
|
||
if (res & Qt::ItemIsSelectable) {
|
||
if (index.row() != 0)
|
||
res |= Qt::ItemIsEditable;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
QVariant TemplatesModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole && index.row() == 0)
|
||
return "(" + QString::fromUtf8(language[lsDefault].c_str()) + ")";
|
||
return BaseModel::data(index, role);
|
||
}
|
||
|
||
void TemplatesModel::setCore(Core *core)
|
||
{
|
||
beginResetModel();
|
||
BaseModel::setCore(core);
|
||
|
||
if (core) {
|
||
ProjectTemplateManager *manager = core->template_manager();
|
||
for (size_t i = 0; i < manager->count(); i++) {
|
||
ProjectTemplate *pt = manager->item(i);
|
||
internalAddTemplate(pt);
|
||
}
|
||
}
|
||
endResetModel();
|
||
}
|
||
|
||
void TemplatesModel::updateTemplate(ProjectTemplate *pt)
|
||
{
|
||
updateNode(internalUpdateTemplate(pt));
|
||
}
|
||
|
||
void TemplatesModel::removeTemplate(ProjectTemplate *pt)
|
||
{
|
||
removeNode(pt);
|
||
}
|
||
|
||
ProjectNode * TemplatesModel::internalUpdateTemplate(ProjectTemplate *pt)
|
||
{
|
||
ProjectNode *node = objectToNode(pt);
|
||
if (!node)
|
||
return NULL;
|
||
|
||
node->setText(QString::fromUtf8(pt->name().c_str()));
|
||
node->setIcon(nodeIcon(node->type()));
|
||
return node;
|
||
}
|
||
|
||
ProjectNode * TemplatesModel::internalAddTemplate(ProjectTemplate *pt)
|
||
{
|
||
beginInsertRows(nodeToIndex(NULL), root()->childCount(), root()->childCount());
|
||
ProjectNode *node = new ProjectNode(root(), NODE_TEMPLATE, (void *)pt);
|
||
endInsertRows();
|
||
|
||
setObjectNode(pt, node);
|
||
internalUpdateTemplate(pt);
|
||
return node;
|
||
}
|
||
|
||
void TemplatesModel::addTemplate(ProjectTemplate * pt)
|
||
{
|
||
updateNode(internalAddTemplate(pt));
|
||
}
|
||
|
||
/**
|
||
* LogModel
|
||
*/
|
||
|
||
LogModel::LogModel(QObject *parent)
|
||
: BaseModel(parent)
|
||
{
|
||
|
||
}
|
||
|
||
void LogModel::addMessage(MessageType type, IObject *sender, const QString &text)
|
||
{
|
||
NodeType node_type;
|
||
QString icon_name;
|
||
if (type == mtWarning) {
|
||
node_type = NODE_WARNING;
|
||
icon_name = ":/images/warning.png";
|
||
} else if (type == mtError) {
|
||
node_type = NODE_ERROR;
|
||
icon_name = ":/images/error.png";
|
||
} else
|
||
node_type = NODE_MESSAGE;
|
||
|
||
ProjectNode *node;
|
||
beginInsertRows(QModelIndex(), root()->childCount(), root()->childCount());
|
||
node = new ProjectNode(root(), node_type, sender);
|
||
endInsertRows();
|
||
|
||
if (sender)
|
||
setObjectNode(sender, node);
|
||
|
||
node->setText(text);
|
||
if (!icon_name.isEmpty())
|
||
node->setIcon(QIcon(icon_name));
|
||
}
|
||
|
||
QVariant LogModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole) {
|
||
return QString::fromUtf8(language[lsCompilationLog].c_str());
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
void LogModel::clear()
|
||
{
|
||
beginRemoveRows(QModelIndex(), 0, root()->childCount());
|
||
BaseModel::clear();
|
||
endRemoveRows();
|
||
}
|
||
|
||
void LogModel::removeObject(void *object)
|
||
{
|
||
removeNode(object);
|
||
}
|
||
|
||
/**
|
||
* ProjectTreeDelegate
|
||
*/
|
||
|
||
ProjectTreeDelegate::ProjectTreeDelegate(QObject *parent)
|
||
: TreeViewItemDelegate(parent)
|
||
{
|
||
|
||
}
|
||
|
||
QWidget *ProjectTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
|
||
{
|
||
QLineEdit *editor = new LineEdit(parent);
|
||
editor->setObjectName("editor");
|
||
editor->setFrame(false);
|
||
|
||
return editor;
|
||
}
|
||
|
||
void ProjectTreeDelegate::setModelData(QWidget *editor, QAbstractItemModel * /*model*/, const QModelIndex &index) const
|
||
{
|
||
ProjectNode *node = static_cast<ProjectNode *>(index.internalPointer());
|
||
if (!node)
|
||
return;
|
||
|
||
auto le = qobject_cast<QLineEdit *>(editor);
|
||
assert(le);
|
||
if (!le)
|
||
return;
|
||
|
||
QString text = le->text();
|
||
|
||
switch (node->type()) {
|
||
case NODE_FOLDER:
|
||
static_cast<Folder *>(node->data())->set_name(text.toUtf8().constData());
|
||
break;
|
||
#ifdef ULTIMATE
|
||
case NODE_LICENSE:
|
||
static_cast<License *>(node->data())->set_customer_name(text.toUtf8().constData());
|
||
break;
|
||
case NODE_FILE_FOLDER:
|
||
static_cast<FileFolder *>(node->data())->set_name(text.toUtf8().constData());
|
||
break;
|
||
case NODE_FILE:
|
||
static_cast<InternalFile *>(node->data())->set_name(text.toUtf8().constData());
|
||
break;
|
||
#endif
|
||
case NODE_WATERMARK:
|
||
static_cast<Watermark *>(node->data())->set_name(text.toUtf8().constData());
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* WatermarksTreeDelegate
|
||
*/
|
||
|
||
WatermarksTreeDelegate::WatermarksTreeDelegate(QObject *parent)
|
||
: TreeViewItemDelegate(parent)
|
||
{
|
||
|
||
}
|
||
|
||
QWidget *WatermarksTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
|
||
{
|
||
QLineEdit *editor = new LineEdit(parent);
|
||
editor->setObjectName("editor");
|
||
editor->setFrame(false);
|
||
|
||
return editor;
|
||
}
|
||
|
||
void WatermarksTreeDelegate::setModelData(QWidget *editor, QAbstractItemModel * /*model*/, const QModelIndex &index) const
|
||
{
|
||
ProjectNode *node = static_cast<ProjectNode *>(index.internalPointer());
|
||
if (!node)
|
||
return;
|
||
|
||
QString text = qobject_cast<QLineEdit *>(editor)->text();
|
||
|
||
switch (node->type()) {
|
||
case NODE_WATERMARK:
|
||
static_cast<Watermark *>(node->data())->set_name(text.toUtf8().constData());
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* TemplatesTreeDelegate
|
||
*/
|
||
|
||
TemplatesTreeDelegate::TemplatesTreeDelegate(QObject *parent)
|
||
: TreeViewItemDelegate(parent)
|
||
{
|
||
|
||
}
|
||
|
||
QWidget *TemplatesTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
|
||
{
|
||
QLineEdit *editor = new LineEdit(parent);
|
||
editor->setObjectName("editor");
|
||
editor->setFrame(false);
|
||
|
||
return editor;
|
||
}
|
||
|
||
void TemplatesTreeDelegate::setModelData(QWidget *editor, QAbstractItemModel * /*model*/, const QModelIndex &index) const
|
||
{
|
||
ProjectNode *node = static_cast<ProjectNode *>(index.internalPointer());
|
||
if (!node)
|
||
return;
|
||
|
||
QString text = qobject_cast<QLineEdit *>(editor)->text();
|
||
if (text.isEmpty())
|
||
{
|
||
//FIXME i18n
|
||
MessageDialog::warning(editor->parentWidget(), "Please provide meaningful name", QMessageBox::Ok);
|
||
return;
|
||
}
|
||
switch (node->type()) {
|
||
case NODE_TEMPLATE:
|
||
static_cast<ProjectTemplate *>(node->data())->set_name(text.toUtf8().constData());
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* DumpModel
|
||
*/
|
||
|
||
DumpModel::DumpModel(QObject *parent)
|
||
: QAbstractItemModel(parent), file_(NULL), rowCountCache_(0), cacheAddress_(0)
|
||
{
|
||
|
||
}
|
||
|
||
QModelIndex DumpModel::index(int row, int column, const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid() && parent.column() != 0)
|
||
return QModelIndex();
|
||
|
||
return createIndex(row, column);
|
||
}
|
||
|
||
QModelIndex DumpModel::parent(const QModelIndex & /*index*/) const
|
||
{
|
||
return QModelIndex();
|
||
}
|
||
|
||
int DumpModel::rowCount(const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid())
|
||
return 0;
|
||
|
||
if(rowCountCache_ == 0) {
|
||
QMapIterator<uint64_t, int> i(addrsToRows_);
|
||
while (i.hasNext()) {
|
||
i.next();
|
||
rowCountCache_ += i.value();
|
||
}
|
||
}
|
||
return rowCountCache_;
|
||
}
|
||
|
||
int DumpModel::columnCount(const QModelIndex & /*parent*/) const
|
||
{
|
||
return 3;
|
||
}
|
||
|
||
void DumpModel::setFile(IArchitecture *file)
|
||
{
|
||
if (file_ == file)
|
||
return;
|
||
|
||
beginResetModel();
|
||
file_ = file;
|
||
rowCountCache_ = 0;
|
||
addrsToRows_.clear();
|
||
cacheAddress_ = 0;
|
||
cache_.clear();
|
||
|
||
if (file_) {
|
||
size_t i;
|
||
ISection *segment;
|
||
std::vector<ISection *> segmentList;
|
||
std::string formatName = file->owner()->format_name();
|
||
|
||
if (formatName == "PE") {
|
||
segment = file->segment_list()->GetSectionByAddress(file->image_base());
|
||
if (segment)
|
||
segmentList.push_back(segment);
|
||
}
|
||
|
||
for (i = 0; i < file->segment_list()->count(); i++) {
|
||
segment = file->segment_list()->item(i);
|
||
if (segment->memory_type() == mtNone || segment->size() == 0)
|
||
continue;
|
||
|
||
if (formatName == "ELF" && segment->name() != "PT_LOAD")
|
||
continue;
|
||
|
||
segmentList.push_back(segment);
|
||
}
|
||
|
||
uint64_t curAddr;
|
||
int curRows = 0;
|
||
for (i = 0; i < segmentList.size(); i++) {
|
||
segment = segment = segmentList[i];
|
||
uint64_t address = segment->address();
|
||
uint32_t rows = (uint32_t)(segment->size() + 15) / 16;
|
||
|
||
if(curRows == 0) {
|
||
curAddr = address;
|
||
curRows = rows;
|
||
continue;
|
||
}
|
||
uint64_t curEndAddr = curAddr + 16 * curRows;
|
||
if(curEndAddr < address) { //gap
|
||
addrsToRows_.insert(curAddr, curRows);
|
||
curAddr = address;
|
||
curRows = rows;
|
||
continue;
|
||
}
|
||
uint64_t nextEndAddr = address + 16 * rows;
|
||
if(nextEndAddr > curEndAddr) curRows = (nextEndAddr - curAddr) / 16;
|
||
}
|
||
if (curRows) addrsToRows_.insert(curAddr, curRows);
|
||
}
|
||
endResetModel();
|
||
}
|
||
|
||
QByteArray DumpModel::read(uint64_t address, int size) const
|
||
{
|
||
if (!cacheAddress_ || address < cacheAddress_ || address + size > cacheAddress_ + cache_.size()) {
|
||
if (file_->AddressSeek(address)) {
|
||
ISection *segment = file_->selected_segment();
|
||
cacheAddress_ = address;
|
||
int cacheSize = (int)qMin(segment->physical_size(), (uint32_t)segment->size()) - (address - segment->address());
|
||
if (cacheSize > 0x100000 && cacheSize > size) // 1Mbyte read ahead limit
|
||
cacheSize = 0x100000;
|
||
if (cacheSize) {
|
||
cache_.resize(cacheSize);
|
||
file_->Read(cache_.data(), cacheSize);
|
||
} else {
|
||
cache_.clear();
|
||
}
|
||
} else {
|
||
return QByteArray();
|
||
}
|
||
}
|
||
|
||
uint64_t offset = address - cacheAddress_;
|
||
return cache_.mid(offset, qMin(cache_.size() - (int)offset, size));
|
||
}
|
||
|
||
QVariant DumpModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if (!index.isValid())
|
||
return QVariant();
|
||
|
||
if (role == Qt::DisplayRole) {
|
||
uint64_t address = indexToAddress(index);
|
||
switch (index.column()) {
|
||
case 0:
|
||
{
|
||
QString res;
|
||
ISection *segment = file_->segment_list()->GetSectionByAddress(address);
|
||
if (segment)
|
||
res = QString::fromLatin1(segment->name().c_str()).append(':');
|
||
res.append(QString::fromUtf8(DisplayValue(file_->cpu_address_size(), address).c_str()));
|
||
return res;
|
||
}
|
||
|
||
case 1:
|
||
{
|
||
QByteArray data = read(address, 0x10);
|
||
unsigned char res[16*3] = "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??";
|
||
static char hex[] = "0123456789ABCDEF";
|
||
for (int i = 0; i < 16; i++) {
|
||
int value = -1;
|
||
if (i < data.size()) {
|
||
value = (unsigned char)data[i];
|
||
} else {
|
||
data = read(address + i, 1);
|
||
if(data.size()) {
|
||
value = (unsigned char)data[0];
|
||
}
|
||
}
|
||
if (value >= 0) {
|
||
res[3 * i] = hex[value >> 4];
|
||
res[3 * i + 1] = hex[value & 0x0f];
|
||
}
|
||
}
|
||
return QString((char *)res);
|
||
}
|
||
|
||
case 2:
|
||
{
|
||
QByteArray data = read(address, 0x10);
|
||
char res[17], *ptr = res;
|
||
for (int i = 0; i < 16; i++) {
|
||
if (i < data.size()) {
|
||
unsigned char value = data[i];
|
||
if (value < 32 || value > 127) value = 0xB7;
|
||
*ptr++ = value;
|
||
} else {
|
||
data = read(address + i, 1);
|
||
if (data.size()) {
|
||
unsigned char value = data[0];
|
||
if (value < 32 || value > 127) value = 0xB7;
|
||
*ptr++ = value;
|
||
}
|
||
else {
|
||
*ptr++ = '?';
|
||
}
|
||
}
|
||
}
|
||
*ptr = 0;
|
||
return QString::fromLatin1((char *)res);
|
||
}
|
||
}
|
||
} else if (role == Qt::FontRole) {
|
||
QFont font(MONOSPACE_FONT_FAMILY);
|
||
return font;
|
||
}
|
||
|
||
return QVariant();
|
||
}
|
||
|
||
QVariant DumpModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole) {
|
||
switch (section) {
|
||
case 0:
|
||
return QString::fromUtf8(language[lsAddress].c_str());
|
||
case 1:
|
||
return QString::fromUtf8(language[lsDump].c_str());
|
||
case 2:
|
||
return QString::fromUtf8(language[lsValue].c_str());
|
||
}
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
QModelIndex DumpModel::addressToIndex(uint64_t address)
|
||
{
|
||
QMapIterator<uint64_t, int> i(addrsToRows_);
|
||
int rows = 0;
|
||
while (i.hasNext()) {
|
||
i.next();
|
||
if(address >= i.key() && i.value() > (int)((address - i.key()) / 16))
|
||
return createIndex(rows + (int)((address - i.key()) / 16), 0);
|
||
rows += i.value();
|
||
}
|
||
return QModelIndex();
|
||
}
|
||
|
||
uint64_t DumpModel::indexToAddress(const QModelIndex &index) const
|
||
{
|
||
QMapIterator<uint64_t, int> i(addrsToRows_);
|
||
int rows = 0;
|
||
while (i.hasNext()) {
|
||
i.next();
|
||
if (rows + i.value() > index.row())
|
||
return i.key() + (index.row() - rows) * 16;
|
||
rows += i.value();
|
||
}
|
||
assert(0);
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* DisasmModel
|
||
*/
|
||
|
||
DisasmModel::DisasmModel(QObject *parent)
|
||
: QAbstractItemModel(parent), file_(NULL), rowCountCache_(0), func_(NULL)
|
||
{
|
||
|
||
}
|
||
|
||
QModelIndex DisasmModel::index(int row, int column, const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid() && parent.column() != 0)
|
||
return QModelIndex();
|
||
|
||
return createIndex(row, column);
|
||
}
|
||
|
||
QModelIndex DisasmModel::parent(const QModelIndex & /*index*/) const
|
||
{
|
||
return QModelIndex();
|
||
}
|
||
|
||
int DisasmModel::rowCount(const QModelIndex &parent) const
|
||
{
|
||
if (parent.isValid())
|
||
return 0;
|
||
|
||
if (rowCountCache_ == 0) {
|
||
QMapIterator<uint64_t, int> i(addrsToRows_);
|
||
while (i.hasNext()) {
|
||
i.next();
|
||
rowCountCache_ += i.value();
|
||
}
|
||
}
|
||
return rowCountCache_;
|
||
}
|
||
|
||
int DisasmModel::columnCount(const QModelIndex & /*parent*/) const
|
||
{
|
||
return 3;
|
||
}
|
||
|
||
QModelIndex DisasmModel::addressToIndex(uint64_t address)
|
||
{
|
||
int row = addressOffset(address);
|
||
if (row >= 0)
|
||
{
|
||
QModelIndex index = createIndex(row, 0);
|
||
if (func_->count()) {
|
||
QModelIndex end = createIndex(index.row() + (int)func_->count(), 2);
|
||
func_->clear();
|
||
dataChanged(index, end);
|
||
}
|
||
return index;
|
||
}
|
||
return QModelIndex();
|
||
}
|
||
|
||
int DisasmModel::addressOffset(uint64_t address) const
|
||
{
|
||
QMapIterator<uint64_t, int> i(addrsToRows_);
|
||
int ret = 0;
|
||
while (i.hasNext()) {
|
||
i.next();
|
||
if (address >= i.key() && i.value() > (int)(address - i.key()))
|
||
{
|
||
return ret + (int)(address - i.key());
|
||
}
|
||
ret += i.value();
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
uint64_t DisasmModel::offsetToAddress(int offset) const
|
||
{
|
||
QMapIterator<uint64_t, int> i(addrsToRows_);
|
||
while (i.hasNext()) {
|
||
i.next();
|
||
if (i.value() > offset)
|
||
{
|
||
return i.key() + offset;
|
||
}
|
||
offset -= i.value();
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
ICommand *DisasmModel::indexToCommand(const QModelIndex &index) const
|
||
{
|
||
if (func_->count()) {
|
||
uint64_t address = func_->item(0)->address();
|
||
int row = addressOffset(address);
|
||
if (row >= 0 && row <= index.row()) {
|
||
size_t commandIndex = index.row() - row;
|
||
if (commandIndex < func_->count())
|
||
return func_->item(commandIndex);
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
void DisasmModel::setFile(IArchitecture *file)
|
||
{
|
||
if (file_ == file)
|
||
return;
|
||
|
||
beginResetModel();
|
||
file_ = file;
|
||
rowCountCache_ = 0;
|
||
addrsToRows_.clear();
|
||
delete func_;
|
||
func_ = NULL;
|
||
|
||
if (file_) {
|
||
size_t i;
|
||
ISection *segment;
|
||
std::vector<ISection *> segmentList;
|
||
std::string formatName = file->owner()->format_name();
|
||
|
||
if (formatName == "PE" && file->AddressSeek(file->image_base()))
|
||
segmentList.push_back(file->selected_segment());
|
||
|
||
for (i = 0; i < file->segment_list()->count(); i++) {
|
||
segment = file->segment_list()->item(i);
|
||
if (segment->memory_type() == mtNone || segment->size() == 0)
|
||
continue;
|
||
|
||
if (formatName == "ELF" && segment->name() != "PT_LOAD")
|
||
continue;
|
||
|
||
segmentList.push_back(segment);
|
||
}
|
||
|
||
uint64_t curAddr;
|
||
int curRows = 0;
|
||
for (i = 0; i < segmentList.size(); i++) {
|
||
segment = segment = segmentList[i];
|
||
uint64_t address = segment->address();
|
||
uint32_t rows = (uint32_t)segment->size();
|
||
|
||
if (curRows == 0) {
|
||
curAddr = address;
|
||
curRows = rows;
|
||
continue;
|
||
}
|
||
uint64_t curEndAddr = curAddr + curRows;
|
||
if (curEndAddr < address) { //gap
|
||
addrsToRows_.insert(curAddr, curRows);
|
||
curAddr = address;
|
||
curRows = rows;
|
||
continue;
|
||
}
|
||
uint64_t nextEndAddr = address + rows;
|
||
if (nextEndAddr > curEndAddr) curRows = nextEndAddr - curAddr;
|
||
}
|
||
if (curRows) addrsToRows_.insert(curAddr, curRows);
|
||
func_ = file->function_list()->CreateFunction(file->cpu_address_size());
|
||
}
|
||
endResetModel();
|
||
}
|
||
|
||
QVariant DisasmModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if (!index.isValid())
|
||
return QVariant();
|
||
|
||
switch (role) {
|
||
case Qt::DisplayRole:
|
||
case Qt::Vmp::StaticTextRole:
|
||
case Qt::Vmp::StaticColorRole:
|
||
{
|
||
if (func_->count() > 100000)
|
||
func_->clear();
|
||
|
||
uint64_t address = offsetToAddress(index.row());
|
||
ICommand *command = NULL;
|
||
if (func_->count()) {
|
||
int startIndex = addressOffset(func_->item(0)->address());
|
||
if (startIndex >= 0 && startIndex <= index.row()) {
|
||
size_t commandIndex = index.row() - startIndex;
|
||
if (commandIndex < func_->count())
|
||
command = func_->item(commandIndex);
|
||
else if (commandIndex == func_->count())
|
||
address = func_->item(func_->count() - 1)->next_address();
|
||
else
|
||
func_->clear();
|
||
} else {
|
||
func_->clear();
|
||
}
|
||
}
|
||
|
||
if (!command)
|
||
command = func_->ParseCommand(*file_, address, true);
|
||
|
||
if (role == Qt::DisplayRole) {
|
||
switch (index.column()) {
|
||
case 0:
|
||
{
|
||
QString res;
|
||
ISection *segment = file_->segment_list()->GetSectionByAddress(address - address % file_->segment_alignment());
|
||
if (segment)
|
||
res = QString::fromLatin1(segment->name().c_str()).append(':');
|
||
return res.append(QString::fromLatin1(command->display_address().c_str()));
|
||
}
|
||
case 1:
|
||
return QString::fromLatin1(command->dump_str().c_str());
|
||
case 2:
|
||
return QString::fromUtf8(command->text().c_str());
|
||
}
|
||
} else if (role == Qt::Vmp::StaticTextRole) {
|
||
if (index.column() == 2 && !command->comment().value.empty())
|
||
return QString::fromUtf8(command->comment().display_value().c_str());
|
||
} else if (role == Qt::Vmp::StaticColorRole) {
|
||
if (index.column() == 2 && !command->comment().value.empty()) {
|
||
switch (command->comment().type) {
|
||
case ttFunction: case ttJmp:
|
||
return QColor(Qt::blue);
|
||
case ttImport:
|
||
return QColor(Qt::darkRed);
|
||
case ttExport:
|
||
return QColor(Qt::red);
|
||
case ttString:
|
||
return QColor(Qt::darkGreen);
|
||
case ttVariable:
|
||
return QColor(Qt::magenta);
|
||
case ttComment:
|
||
return QColor(Qt::gray);
|
||
default:
|
||
return QColor();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case Qt::FontRole: {
|
||
return QFont(MONOSPACE_FONT_FAMILY);
|
||
}
|
||
}
|
||
|
||
return QVariant();
|
||
}
|
||
|
||
QVariant DisasmModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||
{
|
||
if (role == Qt::DisplayRole) {
|
||
switch (section) {
|
||
case 0:
|
||
return QString::fromUtf8(language[lsAddress].c_str());
|
||
case 1:
|
||
return QString::fromUtf8(language[lsDump].c_str());
|
||
case 2:
|
||
return QString::fromUtf8(language[lsCode].c_str());
|
||
}
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
/**
|
||
* ProjectNode
|
||
*/
|
||
|
||
bool ItemModelSearcher::extractMatchingIndexes(const QModelIndex &parent)
|
||
{
|
||
//TODO: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (current_match_ == NULL)
|
||
current_match_ = &match_before_;
|
||
|
||
int rows = where_->rowCount(parent);
|
||
for(int i = 0; i < rows; ++i)
|
||
{
|
||
QModelIndex idx0;
|
||
for(int col = 0; col < where_->columnCount(parent); col++)
|
||
{
|
||
QModelIndex idx = where_->index(i, col, parent);
|
||
if(idx.isValid())
|
||
{
|
||
if(col == 0)
|
||
idx0 = idx;
|
||
if(from_ == idx)
|
||
{
|
||
assert(current_match_ == &match_before_);
|
||
if (match_before_.isValid() && !forward_)
|
||
return true;
|
||
if (!forward_ && !incremental_ && !match_before_.isValid())
|
||
return false;
|
||
current_match_ = &match_after_;
|
||
} else
|
||
{
|
||
bool matched = (idx.data(Qt::DisplayRole).toString() + idx.data(Qt::Vmp::StaticTextRole).toString()).contains(*term_);
|
||
if (matched)
|
||
{
|
||
*current_match_ = idx;
|
||
if (incremental_ && current_match_ == &match_before_ && from_.isValid() && !match_after_.isValid())
|
||
match_after_ = idx; //store wrapped result
|
||
if (from_.isValid() && current_match_ == &match_after_ && forward_)
|
||
return true;
|
||
if (!from_.isValid() && forward_)
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (extractMatchingIndexes(idx0))
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
QModelIndex ItemModelSearcher::find()
|
||
{
|
||
assert(incremental_ == false || forward_ == true); //other modes unsupported
|
||
if(incremental_ == false || forward_ == true)
|
||
{
|
||
bool from_matched = from_.isValid() && (from_.data(Qt::DisplayRole).toString() + from_.data(Qt::Vmp::StaticTextRole).toString()).contains(*term_);
|
||
if(from_matched && incremental_)
|
||
return from_;
|
||
|
||
if (extractMatchingIndexes(QModelIndex()))
|
||
{
|
||
assert(current_match_ && current_match_->isValid());
|
||
return *current_match_;
|
||
}
|
||
// 1. from_ invalid backward
|
||
if (!from_.isValid() && !forward_ && match_before_.isValid())
|
||
{
|
||
return match_before_;
|
||
}
|
||
|
||
// 2. from_ valid incremental_ wrapped
|
||
if (from_.isValid() && incremental_ && match_after_.isValid())
|
||
{
|
||
return match_after_;
|
||
}
|
||
}
|
||
return QModelIndex();
|
||
}
|