mirror of
https://github.com/rizinorg/cutter.git
synced 2025-02-22 14:43:46 +00:00
Implement Editing and Viewing of Types in the Types Widget (#1597)
* Implemet Edit and View for types * Rename LoadNewTypes to TypesInteraction
This commit is contained in:
parent
228d3a454a
commit
5fb2c8ac6f
@ -331,7 +331,7 @@ SOURCES += \
|
|||||||
dialogs/WelcomeDialog.cpp \
|
dialogs/WelcomeDialog.cpp \
|
||||||
common/RunScriptTask.cpp \
|
common/RunScriptTask.cpp \
|
||||||
dialogs/EditMethodDialog.cpp \
|
dialogs/EditMethodDialog.cpp \
|
||||||
dialogs/LoadNewTypesDialog.cpp \
|
dialogs/TypesInteractionDialog.cpp \
|
||||||
widgets/SdbWidget.cpp \
|
widgets/SdbWidget.cpp \
|
||||||
common/PythonManager.cpp \
|
common/PythonManager.cpp \
|
||||||
plugins/PluginManager.cpp \
|
plugins/PluginManager.cpp \
|
||||||
@ -457,7 +457,7 @@ HEADERS += \
|
|||||||
common/Json.h \
|
common/Json.h \
|
||||||
dialogs/EditMethodDialog.h \
|
dialogs/EditMethodDialog.h \
|
||||||
common/CrashHandler.h \
|
common/CrashHandler.h \
|
||||||
dialogs/LoadNewTypesDialog.h \
|
dialogs/TypesInteractionDialog.h \
|
||||||
widgets/SdbWidget.h \
|
widgets/SdbWidget.h \
|
||||||
common/PythonManager.h \
|
common/PythonManager.h \
|
||||||
plugins/PluginManager.h \
|
plugins/PluginManager.h \
|
||||||
@ -532,7 +532,7 @@ FORMS += \
|
|||||||
dialogs/HexdumpRangeDialog.ui \
|
dialogs/HexdumpRangeDialog.ui \
|
||||||
dialogs/WelcomeDialog.ui \
|
dialogs/WelcomeDialog.ui \
|
||||||
dialogs/EditMethodDialog.ui \
|
dialogs/EditMethodDialog.ui \
|
||||||
dialogs/LoadNewTypesDialog.ui \
|
dialogs/TypesInteractionDialog.ui \
|
||||||
widgets/SdbWidget.ui \
|
widgets/SdbWidget.ui \
|
||||||
dialogs/LinkTypeDialog.ui \
|
dialogs/LinkTypeDialog.ui \
|
||||||
widgets/ColorPicker.ui \
|
widgets/ColorPicker.ui \
|
||||||
|
@ -2349,6 +2349,7 @@ QList<TypeDescription> CutterCore::getAllTypedefs()
|
|||||||
|
|
||||||
QString CutterCore::addTypes(const char *str)
|
QString CutterCore::addTypes(const char *str)
|
||||||
{
|
{
|
||||||
|
CORE_LOCK();
|
||||||
char *error_msg = nullptr;
|
char *error_msg = nullptr;
|
||||||
char *parsed = r_parse_c_string(core_->anal, str, &error_msg);
|
char *parsed = r_parse_c_string(core_->anal, str, &error_msg);
|
||||||
QString error;
|
QString error;
|
||||||
@ -2372,6 +2373,26 @@ QString CutterCore::addTypes(const char *str)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString CutterCore::getTypeAsC(QString name, QString category)
|
||||||
|
{
|
||||||
|
CORE_LOCK();
|
||||||
|
QString output = "Failed to fetch the output.";
|
||||||
|
if (name.isEmpty() || category.isEmpty()) {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
QString typeName = sanitizeStringForCommand(name);
|
||||||
|
if (category == "Struct") {
|
||||||
|
output = cmd (QString("tsc %1").arg(typeName));
|
||||||
|
} else if (category == "Union") {
|
||||||
|
output = cmd (QString("tuc %1").arg(typeName));
|
||||||
|
} else if(category == "Enum") {
|
||||||
|
output = cmd (QString("tec %1").arg(typeName));
|
||||||
|
} else if(category == "Typedef") {
|
||||||
|
output = cmd (QString("ttc %1").arg(typeName));
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
bool CutterCore::isAddressMapped(RVA addr)
|
bool CutterCore::isAddressMapped(RVA addr)
|
||||||
{
|
{
|
||||||
// If value returned by "om. @ addr" is empty means that address is not mapped
|
// If value returned by "om. @ addr" is empty means that address is not mapped
|
||||||
|
@ -335,6 +335,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
QList<TypeDescription> getAllTypedefs();
|
QList<TypeDescription> getAllTypedefs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fetching the C representation of a given Type
|
||||||
|
* @param name - the name or the type of the given Type / Struct
|
||||||
|
* @param category - the category of the given Type (Struct, Union, Enum, ...)
|
||||||
|
* @return The type decleration as C output
|
||||||
|
*/
|
||||||
|
QString getTypeAsC(QString name, QString category);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds new types
|
* @brief Adds new types
|
||||||
* It first uses the r_parse_c_string() function from radare2 API to parse the
|
* It first uses the r_parse_c_string() function from radare2 API to parse the
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "dialogs/LoadNewTypesDialog.h"
|
#include "dialogs/TypesInteractionDialog.h"
|
||||||
#include "ui_LoadNewTypesDialog.h"
|
#include "ui_TypesInteractionDialog.h"
|
||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "common/Configuration.h"
|
#include "common/Configuration.h"
|
||||||
@ -9,20 +9,20 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
|
|
||||||
LoadNewTypesDialog::LoadNewTypesDialog(QWidget *parent) :
|
TypesInteractionDialog::TypesInteractionDialog(QWidget *parent, bool readOnly) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::LoadNewTypesDialog)
|
ui(new Ui::TypesInteractionDialog)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->plainTextEdit->setPlainText("");
|
ui->plainTextEdit->setPlainText("");
|
||||||
syntaxHighLighter = new SyntaxHighlighter(ui->plainTextEdit->document());
|
syntaxHighLighter = new SyntaxHighlighter(ui->plainTextEdit->document());
|
||||||
|
|
||||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||||
|
ui->plainTextEdit->setReadOnly(readOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadNewTypesDialog::~LoadNewTypesDialog() {}
|
TypesInteractionDialog::~TypesInteractionDialog() {}
|
||||||
|
|
||||||
void LoadNewTypesDialog::on_selectFileButton_clicked()
|
void TypesInteractionDialog::on_selectFileButton_clicked()
|
||||||
{
|
{
|
||||||
QString filename = QFileDialog::getOpenFileName(this, tr("Select file"), Config()->getRecentFolder(), "Header files (*.h *.hpp);;All files (*)");
|
QString filename = QFileDialog::getOpenFileName(this, tr("Select file"), Config()->getRecentFolder(), "Header files (*.h *.hpp);;All files (*)");
|
||||||
if (filename.isEmpty()) {
|
if (filename.isEmpty()) {
|
||||||
@ -39,7 +39,7 @@ void LoadNewTypesDialog::on_selectFileButton_clicked()
|
|||||||
ui->plainTextEdit->setPlainText(file.readAll());
|
ui->plainTextEdit->setPlainText(file.readAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadNewTypesDialog::on_plainTextEdit_textChanged()
|
void TypesInteractionDialog::on_plainTextEdit_textChanged()
|
||||||
{
|
{
|
||||||
if (ui->plainTextEdit->toPlainText().isEmpty()) {
|
if (ui->plainTextEdit->toPlainText().isEmpty()) {
|
||||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||||
@ -48,7 +48,7 @@ void LoadNewTypesDialog::on_plainTextEdit_textChanged()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadNewTypesDialog::done(int r)
|
void TypesInteractionDialog::done(int r)
|
||||||
{
|
{
|
||||||
if (r == QDialog::Accepted) {
|
if (r == QDialog::Accepted) {
|
||||||
QString error = Core()->addTypes(ui->plainTextEdit->toPlainText());
|
QString error = Core()->addTypes(ui->plainTextEdit->toPlainText());
|
||||||
@ -68,3 +68,8 @@ void LoadNewTypesDialog::done(int r)
|
|||||||
QDialog::done(r);
|
QDialog::done(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypesInteractionDialog::fillTextArea(QString content) {
|
||||||
|
ui->layoutWidget->hide();
|
||||||
|
ui->plainTextEdit->setPlainText(content);
|
||||||
|
}
|
@ -1,21 +1,30 @@
|
|||||||
#ifndef LOADNEWTYPESDIALOG_H
|
#ifndef TYPESINTERACTIONDIALOG_H
|
||||||
#define LOADNEWTYPESDIALOG_H
|
#define TYPESINTERACTIONDIALOG_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class LoadNewTypesDialog;
|
class TypesInteractionDialog;
|
||||||
}
|
}
|
||||||
class SyntaxHighlighter;
|
class SyntaxHighlighter;
|
||||||
|
|
||||||
class LoadNewTypesDialog : public QDialog
|
class TypesInteractionDialog : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LoadNewTypesDialog(QWidget *parent = nullptr);
|
explicit TypesInteractionDialog(QWidget *parent = nullptr, bool readOnly = false);
|
||||||
~LoadNewTypesDialog();
|
~TypesInteractionDialog();
|
||||||
|
/**
|
||||||
|
* @brief Fill the Dialog's TextEdit object with the content
|
||||||
|
* passed to the function. The content will most likely be a C
|
||||||
|
* representation of a Type.
|
||||||
|
* @param content - The content which should be in the TextEdit object.
|
||||||
|
* most likely will be a C representation of a Type.
|
||||||
|
* @param readonly - Will be set as "true" for viewing mode
|
||||||
|
*/
|
||||||
|
void fillTextArea(QString content);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
/**
|
/**
|
||||||
@ -38,7 +47,7 @@ private slots:
|
|||||||
void done(int r) override;
|
void done(int r) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::LoadNewTypesDialog> ui;
|
std::unique_ptr<Ui::TypesInteractionDialog> ui;
|
||||||
SyntaxHighlighter *syntaxHighLighter;
|
SyntaxHighlighter *syntaxHighLighter;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@ -48,4 +57,4 @@ signals:
|
|||||||
void newTypesLoaded();
|
void newTypesLoaded();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOADNEWTYPESDIALOG_H
|
#endif // TYPESINTERACTIONDIALOG_H
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>LoadNewTypesDialog</class>
|
<class>TypesInteractionDialog</class>
|
||||||
<widget class="QDialog" name="LoadNewTypesDialog">
|
<widget class="QDialog" name="TypesInteractionDialog">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
@ -15,6 +15,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
|
<widget class="QWidget" name="layoutWidget" native="true">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="filenameLabel">
|
<widget class="QLabel" name="filenameLabel">
|
||||||
@ -38,6 +39,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPlainTextEdit" name="plainTextEdit">
|
<widget class="QPlainTextEdit" name="plainTextEdit">
|
||||||
@ -66,7 +68,7 @@
|
|||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
<signal>accepted()</signal>
|
<signal>accepted()</signal>
|
||||||
<receiver>LoadNewTypesDialog</receiver>
|
<receiver>TypesInteractionDialog</receiver>
|
||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
@ -82,7 +84,7 @@
|
|||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
<signal>rejected()</signal>
|
<signal>rejected()</signal>
|
||||||
<receiver>LoadNewTypesDialog</receiver>
|
<receiver>TypesInteractionDialog</receiver>
|
||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
@ -2,7 +2,7 @@
|
|||||||
#include "ui_TypesWidget.h"
|
#include "ui_TypesWidget.h"
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
#include "dialogs/LoadNewTypesDialog.h"
|
#include "dialogs/TypesInteractionDialog.h"
|
||||||
#include "dialogs/LinkTypeDialog.h"
|
#include "dialogs/LinkTypeDialog.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
@ -60,7 +60,7 @@ QVariant TypesModel::headerData(int section, Qt::Orientation, int role) const
|
|||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
switch (section) {
|
switch (section) {
|
||||||
case TYPE:
|
case TYPE:
|
||||||
return tr("Type");
|
return tr("Type / Name");
|
||||||
case SIZE:
|
case SIZE:
|
||||||
return tr("Size");
|
return tr("Size");
|
||||||
case FORMAT:
|
case FORMAT:
|
||||||
@ -181,6 +181,13 @@ TypesWidget::TypesWidget(MainWindow *main, QAction *action) :
|
|||||||
tree->showItemsNumber(types_proxy_model->rowCount());
|
tree->showItemsNumber(types_proxy_model->rowCount());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
actionViewType = new QAction(tr("View Type"), this);
|
||||||
|
actionEditType = new QAction(tr("Edit Type"), this);
|
||||||
|
|
||||||
|
connect (actionViewType, &QAction::triggered, [this]() { viewType(true) ;});
|
||||||
|
connect (actionEditType, &QAction::triggered, [this]() { viewType(false) ;});
|
||||||
|
connect (ui->typesTreeView, &QTreeView::doubleClicked, this, &TypesWidget::typeItemDoubleClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypesWidget::~TypesWidget() {}
|
TypesWidget::~TypesWidget() {}
|
||||||
@ -229,11 +236,15 @@ void TypesWidget::showTypesContextMenu(const QPoint &pt)
|
|||||||
|
|
||||||
if (index.isValid()) {
|
if (index.isValid()) {
|
||||||
TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value<TypeDescription>();
|
TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value<TypeDescription>();
|
||||||
if (t.category == "Struct") {
|
if (t.category != "Primitive") {
|
||||||
// Add "Link To Address" option
|
// Add "Link To Address" option
|
||||||
|
menu.addAction(actionViewType);
|
||||||
|
menu.addAction(actionEditType);
|
||||||
|
if (t.category == "Struct") {
|
||||||
menu.addAction(ui->actionLink_Type_To_Address);
|
menu.addAction(ui->actionLink_Type_To_Address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
menu.addAction(ui->actionExport_Types);
|
menu.addAction(ui->actionExport_Types);
|
||||||
|
|
||||||
@ -268,12 +279,34 @@ void TypesWidget::on_actionExport_Types_triggered()
|
|||||||
|
|
||||||
void TypesWidget::on_actionLoad_New_Types_triggered()
|
void TypesWidget::on_actionLoad_New_Types_triggered()
|
||||||
{
|
{
|
||||||
LoadNewTypesDialog dialog(this);
|
TypesInteractionDialog dialog(this);
|
||||||
connect(&dialog, SIGNAL(newTypesLoaded()), this, SLOT(refreshTypes()));
|
connect(&dialog, &TypesInteractionDialog::newTypesLoaded, this, &TypesWidget::refreshTypes);
|
||||||
dialog.setWindowTitle(tr("Load New Types"));
|
dialog.setWindowTitle(tr("Load New Types"));
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypesWidget::viewType(bool readOnly)
|
||||||
|
{
|
||||||
|
|
||||||
|
QModelIndex index = ui->typesTreeView->currentIndex();
|
||||||
|
|
||||||
|
if (!index.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypesInteractionDialog dialog(this, readOnly);
|
||||||
|
TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value<TypeDescription>();
|
||||||
|
if (!readOnly) {
|
||||||
|
dialog.setWindowTitle(tr("Edit Type: ") + t.type);
|
||||||
|
connect(&dialog, &TypesInteractionDialog::newTypesLoaded, this, &TypesWidget::refreshTypes);
|
||||||
|
} else {
|
||||||
|
dialog.setWindowTitle(tr("View Type: ") + t.type + tr(" (Read Only)"));
|
||||||
|
}
|
||||||
|
dialog.fillTextArea(Core()->getTypeAsC(t.type, t.category));
|
||||||
|
dialog.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void TypesWidget::on_actionDelete_Type_triggered()
|
void TypesWidget::on_actionDelete_Type_triggered()
|
||||||
{
|
{
|
||||||
QModelIndex proxyIndex = ui->typesTreeView->currentIndex();
|
QModelIndex proxyIndex = ui->typesTreeView->currentIndex();
|
||||||
@ -301,7 +334,21 @@ void TypesWidget::on_actionLink_Type_To_Address_triggered()
|
|||||||
TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value<TypeDescription>();
|
TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value<TypeDescription>();
|
||||||
dialog.setDefaultType(t.type);
|
dialog.setDefaultType(t.type);
|
||||||
dialog.setDefaultAddress(RAddressString(Core()->getOffset()));
|
dialog.setDefaultAddress(RAddressString(Core()->getOffset()));
|
||||||
|
dialog.exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypesWidget::typeItemDoubleClicked(const QModelIndex &index) {
|
||||||
|
if (!index.isValid()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypesInteractionDialog dialog(this, true);
|
||||||
|
TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value<TypeDescription>();
|
||||||
|
if (t.category == "Primitive") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dialog.fillTextArea(Core()->getTypeAsC(t.type, t.category));
|
||||||
|
dialog.setWindowTitle(tr("View Type: ") + t.type + tr(" (Read Only)"));
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
}
|
}
|
||||||
|
@ -93,11 +93,19 @@ private slots:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Executed on clicking the Load New types option in the context menu
|
* @brief Executed on clicking the Load New types option in the context menu
|
||||||
* It will open the LoadNewTypesDialog where the user can either enter the
|
* It will open the TypesInteractionDialog where the user can either enter the
|
||||||
* types manually, or can select a file from where the types will be loaded
|
* types manually, or can select a file from where the types will be loaded
|
||||||
*/
|
*/
|
||||||
void on_actionLoad_New_Types_triggered();
|
void on_actionLoad_New_Types_triggered();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Executed on clicking either the Edit Type or View Type options in the context menu
|
||||||
|
* It will open the TypesInteractionDialog filled with the selected type. Depends on Edit or View mode
|
||||||
|
* the text view would be read-only or not.
|
||||||
|
*/
|
||||||
|
void viewType(bool readOnly=true);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Executed on clicking the Delete Type option in the context menu
|
* @brief Executed on clicking the Delete Type option in the context menu
|
||||||
* Upon confirmation from the user, it will delete the selected type.
|
* Upon confirmation from the user, it will delete the selected type.
|
||||||
@ -110,6 +118,12 @@ private slots:
|
|||||||
*/
|
*/
|
||||||
void on_actionLink_Type_To_Address_triggered();
|
void on_actionLink_Type_To_Address_triggered();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief triggers when the user double-clicks an item. This will open
|
||||||
|
* a dialog that shows the Type's content
|
||||||
|
*/
|
||||||
|
void typeItemDoubleClicked(const QModelIndex &index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::TypesWidget> ui;
|
std::unique_ptr<Ui::TypesWidget> ui;
|
||||||
|
|
||||||
@ -117,6 +131,8 @@ private:
|
|||||||
TypesSortFilterProxyModel *types_proxy_model;
|
TypesSortFilterProxyModel *types_proxy_model;
|
||||||
QList<TypeDescription> types;
|
QList<TypeDescription> types;
|
||||||
CutterTreeWidget *tree;
|
CutterTreeWidget *tree;
|
||||||
|
QAction *actionViewType;
|
||||||
|
QAction *actionEditType;
|
||||||
|
|
||||||
void setScrollMode();
|
void setScrollMode();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user