mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-19 19:36:11 +00:00
c4e8a1c178
* Small refactor for the widgets of Cutter This refactor include the following : * Creation of a new class Creation of a new class, named CutterWidget, that inherits from QDockWidget and is used to represent all of the widgets of the main window. The goal of this class is to regroup all the behaviour shared by the widgets of Cutter. For example : in the constructor, instructions corresponding of those present in the macro **ADD_DOCK** (in MainWindow.cpp) are executed. This was made because I think that the macro **ADD_DOCK** which is used to construct the widgets does not take advantage of the object structure. * Ensure that every widget has a parent Some widgets were created using the constructor QDockWidget, but using **nullptr** (default) as argument, thus they haven't got any parent. The constructor of a CutterWidget takes as argument the MainWindow and an action (optional) and calls the constructor of QDockWidget with the main window as argument. This is valid under the assumption that it is mandatory for every widget to have the main window as a parent. * Constructors removal The constructors of some widgets are not used anywhere and does not seem not fullfill any current usecase. They were removed. * Renaming CutterWidget to CutterDockWidget
773 lines
21 KiB
C++
773 lines
21 KiB
C++
#include "MainWindow.h"
|
|
#include "ui_MainWindow.h"
|
|
#include "dialogs/CommentsDialog.h"
|
|
#include "dialogs/AboutDialog.h"
|
|
#include "dialogs/RenameDialog.h"
|
|
#include "dialogs/preferences/PreferencesDialog.h"
|
|
#include "utils/Helpers.h"
|
|
|
|
#include <QApplication>
|
|
#include <QComboBox>
|
|
#include <QCompleter>
|
|
#include <QDebug>
|
|
#include <QDesktopServices>
|
|
#include <QDir>
|
|
#include <QDockWidget>
|
|
#include <QFile>
|
|
#include <QFileDialog>
|
|
#include <QFont>
|
|
#include <QFontDialog>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QList>
|
|
#include <QMessageBox>
|
|
#include <QProcess>
|
|
#include <QPropertyAnimation>
|
|
#include <QScrollBar>
|
|
#include <QSettings>
|
|
#include <QShortcut>
|
|
#include <QStringListModel>
|
|
#include <QStyledItemDelegate>
|
|
#include <QStyleFactory>
|
|
#include <QTextCursor>
|
|
#include <QtGlobal>
|
|
#include <QToolButton>
|
|
#include <QToolTip>
|
|
#include <QTreeWidgetItem>
|
|
#include <QSvgRenderer>
|
|
|
|
#include "utils/Highlighter.h"
|
|
#include "utils/HexAsciiHighlighter.h"
|
|
#include "utils/Helpers.h"
|
|
#include "utils/SvgIconEngine.h"
|
|
|
|
#include "dialogs/NewFileDialog.h"
|
|
#include "widgets/DisassemblerGraphView.h"
|
|
#include "widgets/GraphWidget.h"
|
|
#include "widgets/FunctionsWidget.h"
|
|
#include "widgets/SectionsWidget.h"
|
|
#include "widgets/CommentsWidget.h"
|
|
#include "widgets/ImportsWidget.h"
|
|
#include "widgets/ExportsWidget.h"
|
|
#include "widgets/TypesWidget.h"
|
|
#include "widgets/SearchWidget.h"
|
|
#include "widgets/SymbolsWidget.h"
|
|
#include "widgets/StringsWidget.h"
|
|
#include "widgets/SectionsDock.h"
|
|
#include "widgets/RelocsWidget.h"
|
|
#include "widgets/FlagsWidget.h"
|
|
#include "widgets/VisualNavbar.h"
|
|
#include "widgets/Dashboard.h"
|
|
#include "widgets/Sidebar.h"
|
|
#include "widgets/SdbDock.h"
|
|
#include "widgets/Omnibar.h"
|
|
#include "widgets/ConsoleWidget.h"
|
|
#include "dialogs/OptionsDialog.h"
|
|
#include "widgets/EntrypointWidget.h"
|
|
#include "dialogs/SaveProjectDialog.h"
|
|
#include "widgets/ClassesWidget.h"
|
|
#include "widgets/ResourcesWidget.h"
|
|
#include "widgets/VTablesWidget.h"
|
|
#include "widgets/JupyterWidget.h"
|
|
|
|
// graphics
|
|
#include <QGraphicsEllipseItem>
|
|
#include <QGraphicsScene>
|
|
#include <QGraphicsView>
|
|
|
|
#include <cassert>
|
|
|
|
static void registerCustomFonts()
|
|
{
|
|
int ret = QFontDatabase::addApplicationFont(":/fonts/Anonymous Pro.ttf");
|
|
assert(-1 != ret && "unable to register Anonymous Pro.ttf");
|
|
|
|
ret = QFontDatabase::addApplicationFont(":/fonts/Inconsolata-Regular.ttf");
|
|
assert(-1 != ret && "unable to register Inconsolata-Regular.ttf");
|
|
|
|
// Do not issue a warning in release
|
|
Q_UNUSED(ret)
|
|
}
|
|
|
|
MainWindow::MainWindow(QWidget *parent) :
|
|
QMainWindow(parent),
|
|
core(Core()),
|
|
ui(new Ui::MainWindow)
|
|
{
|
|
panelLock = false;
|
|
tabsOnTop = false;
|
|
configuration = Config();
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
}
|
|
|
|
void MainWindow::initUI()
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
registerCustomFonts();
|
|
|
|
/*
|
|
* Toolbar
|
|
*/
|
|
// Hide central tab widget tabs
|
|
QTabBar *centralbar = ui->centralTabWidget->tabBar();
|
|
centralbar->setVisible(false);
|
|
|
|
// Sepparator between undo/redo and goto lineEdit
|
|
QWidget *spacer3 = new QWidget();
|
|
spacer3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
spacer3->setMinimumSize(20, 20);
|
|
spacer3->setMaximumWidth(300);
|
|
ui->mainToolBar->addWidget(spacer3);
|
|
|
|
// Omnibar LineEdit
|
|
this->omnibar = new Omnibar(this);
|
|
ui->mainToolBar->addWidget(this->omnibar);
|
|
|
|
// Add special separators to the toolbar that expand to separate groups of elements
|
|
QWidget *spacer2 = new QWidget();
|
|
spacer2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
spacer2->setMinimumSize(10, 10);
|
|
spacer2->setMaximumWidth(300);
|
|
ui->mainToolBar->addWidget(spacer2);
|
|
|
|
// Separator between back/forward and undo/redo buttons
|
|
QWidget *spacer = new QWidget();
|
|
spacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
|
spacer->setMinimumSize(20, 20);
|
|
ui->mainToolBar->addWidget(spacer);
|
|
|
|
// Visual navigation tool bar
|
|
this->visualNavbar = new VisualNavbar(this);
|
|
this->visualNavbar->setMovable(false);
|
|
addToolBarBreak(Qt::TopToolBarArea);
|
|
addToolBar(visualNavbar);
|
|
|
|
/*
|
|
* Dock Widgets
|
|
*/
|
|
dockWidgets.reserve(20);
|
|
|
|
disassemblyDock = new DisassemblyWidget(this, ui->actionDisassembly);
|
|
sidebarDock = new SidebarWidget(this, ui->actionSidebar);
|
|
hexdumpDock = new HexdumpWidget(this, ui->actionHexdump);
|
|
pseudocodeDock = new PseudocodeWidget(this, ui->actionPseudocode);
|
|
consoleDock = new ConsoleWidget(this, ui->actionConsole);
|
|
|
|
// Add graph view as dockable
|
|
graphDock = new GraphWidget(this, ui->actionGraph);
|
|
|
|
// Hide centralWidget as we do not need it
|
|
ui->centralWidget->hide();
|
|
|
|
sectionsDock = new SectionsDock(this, ui->actionSections);
|
|
disassemblyDock = new DisassemblyWidget(this, ui->actionDisassembly);
|
|
entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints);
|
|
functionsDock = new FunctionsWidget(this, ui->actionFunctions);
|
|
importsDock = new ImportsWidget(this, ui->actionImports);
|
|
exportsDock = new ExportsWidget(this, ui->actionExports);
|
|
typesDock = new TypesWidget(this, ui->actionTypes);
|
|
searchDock = new SearchWidget(this, ui->actionSearch);
|
|
symbolsDock = new SymbolsWidget(this, ui->actionSymbols);
|
|
relocsDock = new RelocsWidget(this, ui->actionRelocs);
|
|
commentsDock = new CommentsWidget(this, ui->actionComments);
|
|
stringsDock = new StringsWidget(this, ui->actionStrings);
|
|
flagsDock = new FlagsWidget(this, ui->actionFlags);
|
|
#ifdef CUTTER_ENABLE_JUPYTER
|
|
jupyterDock = new JupyterWidget(this, ui->actionJupyter);
|
|
#else
|
|
ui->actionJupyter->setEnabled(false);
|
|
ui->actionJupyter->setVisible(false);
|
|
#endif
|
|
dashboardDock = new Dashboard(this, ui->actionDashboard);
|
|
disassemblyDock = new DisassemblyWidget(this, ui->actionDisassembly);
|
|
sdbDock = new SdbDock(this, ui->actionSDBBrowser);
|
|
classesDock = new ClassesWidget(this, ui->actionClasses);
|
|
resourcesDock = new ResourcesWidget(this, ui->actionResources);
|
|
vTablesDock = new VTablesWidget(this, ui->actionVTables);
|
|
|
|
|
|
// Set up dock widgets default layout
|
|
resetToDefaultLayout();
|
|
|
|
// Restore saved settings
|
|
this->readSettings();
|
|
// TODO: Allow the user to select this option visually in the GUI settings
|
|
// Adjust the DockWidget areas
|
|
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
|
|
//setCorner( Qt::TopRightCorner, Qt::RightDockWidgetArea );
|
|
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
|
|
//setCorner( Qt::BottomRightCorner, Qt::RightDockWidgetArea );
|
|
|
|
|
|
/*
|
|
* Some global shortcuts
|
|
*/
|
|
// Period goes to command entry
|
|
QShortcut *cmd_shortcut = new QShortcut(QKeySequence(Qt::Key_Period), this);
|
|
connect(cmd_shortcut, SIGNAL(activated()), consoleDock, SLOT(focusInputLineEdit()));
|
|
|
|
// G and S goes to goto entry
|
|
QShortcut *goto_shortcut = new QShortcut(QKeySequence(Qt::Key_G), this);
|
|
connect(goto_shortcut, SIGNAL(activated()), this->omnibar, SLOT(setFocus()));
|
|
QShortcut *seek_shortcut = new QShortcut(QKeySequence(Qt::Key_S), this);
|
|
connect(seek_shortcut, SIGNAL(activated()), this->omnibar, SLOT(setFocus()));
|
|
|
|
QShortcut *refresh_shortcut = new QShortcut(QKeySequence(QKeySequence::Refresh), this);
|
|
connect(refresh_shortcut, SIGNAL(activated()), this, SLOT(refreshAll()));
|
|
|
|
connect(core, SIGNAL(projectSaved(const QString &)), this, SLOT(projectSaved(const QString &)));
|
|
}
|
|
|
|
void MainWindow::openNewFile(const QString &fn, int analLevel, QList<QString> advancedOptions)
|
|
{
|
|
setFilename(fn);
|
|
|
|
/* Reset config */
|
|
core->resetDefaultAsmOptions();
|
|
|
|
/* Prompt to load filename.r2 script */
|
|
QString script = QString("%1.r2").arg(this->filename);
|
|
if (r_file_exists(script.toStdString().data())) {
|
|
QMessageBox mb;
|
|
mb.setWindowTitle(tr("Script loading"));
|
|
mb.setText(tr("Do you want to load the '%1' script?").arg(script));
|
|
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
|
if (mb.exec() == QMessageBox::Yes) {
|
|
core->loadScript(script);
|
|
}
|
|
}
|
|
|
|
/* Show analysis options dialog */
|
|
displayAnalysisOptionsDialog(analLevel, advancedOptions);
|
|
}
|
|
|
|
void MainWindow::displayNewFileDialog()
|
|
{
|
|
NewFileDialog *n = new NewFileDialog();
|
|
newFileDialog = n;
|
|
n->setAttribute(Qt::WA_DeleteOnClose);
|
|
n->show();
|
|
}
|
|
|
|
void MainWindow::closeNewFileDialog()
|
|
{
|
|
if (newFileDialog) {
|
|
newFileDialog->close();
|
|
}
|
|
newFileDialog = nullptr;
|
|
}
|
|
|
|
void MainWindow::displayAnalysisOptionsDialog(int analLevel, QList<QString> advancedOptions)
|
|
{
|
|
OptionsDialog *o = new OptionsDialog(this);
|
|
o->setAttribute(Qt::WA_DeleteOnClose);
|
|
o->show();
|
|
|
|
if (analLevel >= 0)
|
|
{
|
|
o->setupAndStartAnalysis(analLevel, advancedOptions);
|
|
}
|
|
}
|
|
|
|
void MainWindow::openProject(const QString &project_name)
|
|
{
|
|
QString filename = core->cmd("Pi " + project_name);
|
|
setFilename(filename.trimmed());
|
|
|
|
core->openProject(project_name);
|
|
|
|
initUI();
|
|
finalizeOpen();
|
|
}
|
|
|
|
void MainWindow::finalizeOpen()
|
|
{
|
|
core->getOpcodes();
|
|
|
|
// Set settings to override any incorrect saved in the project
|
|
core->setSettings();
|
|
|
|
|
|
addOutput(tr(" > Populating UI"));
|
|
// FIXME: initialization order frakup. the next line is needed so that the
|
|
// comments widget displays the function names.
|
|
core->cmd("fs sections");
|
|
refreshAll();
|
|
|
|
addOutput(tr(" > Finished, happy reversing :)"));
|
|
// Add fortune message
|
|
addOutput("\n" + core->cmd("fo"));
|
|
//previewDock->setWindowTitle("entry0");
|
|
showMaximized();
|
|
}
|
|
|
|
bool MainWindow::saveProject(bool quit)
|
|
{
|
|
QString projectName = core->getConfig("prj.name");
|
|
if (projectName.isEmpty())
|
|
{
|
|
return saveProjectAs(quit);
|
|
}
|
|
else
|
|
{
|
|
core->saveProject(projectName);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool MainWindow::saveProjectAs(bool quit)
|
|
{
|
|
SaveProjectDialog dialog(quit, this);
|
|
int result = dialog.exec();
|
|
|
|
return !quit || result != SaveProjectDialog::Rejected;
|
|
}
|
|
|
|
void MainWindow::refreshOmniBar(const QStringList &flags)
|
|
{
|
|
omnibar->refresh(flags);
|
|
}
|
|
|
|
void MainWindow::setFilename(const QString &fn)
|
|
{
|
|
// Add file name to window title
|
|
this->filename = fn;
|
|
this->setWindowTitle(APPNAME" - " + fn);
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
QMessageBox::StandardButton ret = QMessageBox::question(this, APPNAME,
|
|
tr("Do you really want to exit?\nSave your project before closing!"),
|
|
(QMessageBox::StandardButtons)(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel));
|
|
if (ret == QMessageBox::Save)
|
|
{
|
|
if (saveProject(true))
|
|
{
|
|
saveSettings();
|
|
}
|
|
QMainWindow::closeEvent(event);
|
|
}
|
|
else if (ret == QMessageBox::Discard)
|
|
{
|
|
saveSettings();
|
|
QMainWindow::closeEvent(event);
|
|
}
|
|
else
|
|
{
|
|
event->ignore();
|
|
}
|
|
}
|
|
|
|
void MainWindow::readSettings()
|
|
{
|
|
QSettings settings;
|
|
QByteArray geo = settings.value("geometry", QByteArray()).toByteArray();
|
|
restoreGeometry(geo);
|
|
QByteArray state = settings.value("state", QByteArray()).toByteArray();
|
|
restoreState(state);
|
|
this->responsive = settings.value("responsive").toBool();
|
|
panelLock = settings.value("panelLock").toBool();
|
|
setPanelLock();
|
|
tabsOnTop = settings.value("tabsOnTop").toBool();
|
|
setTabLocation();
|
|
updateDockActionsChecked();
|
|
}
|
|
|
|
void MainWindow::saveSettings()
|
|
{
|
|
QSettings settings;
|
|
settings.setValue("geometry", saveGeometry());
|
|
settings.setValue("size", size());
|
|
settings.setValue("pos", pos());
|
|
settings.setValue("state", saveState());
|
|
settings.setValue("panelLock", panelLock);
|
|
settings.setValue("tabsOnTop", tabsOnTop);
|
|
}
|
|
|
|
void MainWindow::setPanelLock()
|
|
{
|
|
if (panelLock)
|
|
{
|
|
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>())
|
|
{
|
|
dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
|
|
}
|
|
|
|
ui->actionLock->setChecked(false);
|
|
}
|
|
else
|
|
{
|
|
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>())
|
|
{
|
|
dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
|
|
}
|
|
|
|
ui->actionLock->setChecked(true);
|
|
}
|
|
}
|
|
|
|
void MainWindow::setTabLocation()
|
|
{
|
|
if (tabsOnTop)
|
|
{
|
|
ui->centralTabWidget->setTabPosition(QTabWidget::North);
|
|
this->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
|
|
ui->actionTabs_on_Top->setChecked(true);
|
|
}
|
|
else
|
|
{
|
|
ui->centralTabWidget->setTabPosition(QTabWidget::South);
|
|
this->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::South);
|
|
ui->actionTabs_on_Top->setChecked(false);
|
|
}
|
|
}
|
|
|
|
void MainWindow::refreshAll()
|
|
{
|
|
Core()->triggerRefreshAll();
|
|
}
|
|
|
|
void MainWindow::lockUnlock_Docks(bool what)
|
|
{
|
|
if (what)
|
|
{
|
|
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>())
|
|
{
|
|
dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>())
|
|
{
|
|
dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void MainWindow::restoreDocks()
|
|
{
|
|
// In the upper half the functions are the first widget
|
|
addDockWidget(Qt::TopDockWidgetArea, functionsDock);
|
|
|
|
// Function | Dashboard | Sidebar
|
|
splitDockWidget(functionsDock, dashboardDock, Qt::Horizontal);
|
|
splitDockWidget(dashboardDock, sidebarDock, Qt::Horizontal);
|
|
|
|
// In the lower half the console is the first widget
|
|
addDockWidget(Qt::BottomDockWidgetArea, consoleDock);
|
|
|
|
// Console | Sections
|
|
splitDockWidget(consoleDock, sectionsDock, Qt::Horizontal);
|
|
|
|
// Tabs for center (must be applied after splitDockWidget())
|
|
tabifyDockWidget(sectionsDock, commentsDock);
|
|
tabifyDockWidget(dashboardDock, disassemblyDock);
|
|
tabifyDockWidget(dashboardDock, graphDock);
|
|
tabifyDockWidget(dashboardDock, hexdumpDock);
|
|
tabifyDockWidget(dashboardDock, pseudocodeDock);
|
|
tabifyDockWidget(dashboardDock, entrypointDock);
|
|
tabifyDockWidget(dashboardDock, flagsDock);
|
|
tabifyDockWidget(dashboardDock, stringsDock);
|
|
tabifyDockWidget(dashboardDock, relocsDock);
|
|
tabifyDockWidget(dashboardDock, importsDock);
|
|
tabifyDockWidget(dashboardDock, exportsDock);
|
|
tabifyDockWidget(dashboardDock, typesDock);
|
|
tabifyDockWidget(dashboardDock, searchDock);
|
|
tabifyDockWidget(dashboardDock, symbolsDock);
|
|
tabifyDockWidget(dashboardDock, classesDock);
|
|
tabifyDockWidget(dashboardDock, resourcesDock);
|
|
tabifyDockWidget(dashboardDock, vTablesDock);
|
|
#ifdef CUTTER_ENABLE_JUPYTER
|
|
tabifyDockWidget(dashboardDock, jupyterDock);
|
|
#endif
|
|
|
|
updateDockActionsChecked();
|
|
}
|
|
|
|
|
|
void MainWindow::hideAllDocks()
|
|
{
|
|
for (auto w : dockWidgets)
|
|
{
|
|
removeDockWidget(w);
|
|
}
|
|
|
|
updateDockActionsChecked();
|
|
}
|
|
|
|
void MainWindow::updateDockActionsChecked()
|
|
{
|
|
for(auto i=dockWidgetActions.constBegin(); i!=dockWidgetActions.constEnd(); i++)
|
|
{
|
|
i.key()->setChecked(!i.value()->isHidden());
|
|
}
|
|
}
|
|
|
|
void MainWindow::showDefaultDocks()
|
|
{
|
|
const QList<QDockWidget *> defaultDocks = { sectionsDock,
|
|
entrypointDock,
|
|
functionsDock,
|
|
commentsDock,
|
|
stringsDock,
|
|
consoleDock,
|
|
importsDock,
|
|
symbolsDock,
|
|
graphDock,
|
|
disassemblyDock,
|
|
sidebarDock,
|
|
hexdumpDock,
|
|
pseudocodeDock,
|
|
dashboardDock,
|
|
#ifdef CUTTER_ENABLE_JUPYTER
|
|
jupyterDock
|
|
#endif
|
|
};
|
|
|
|
for (auto w : dockWidgets)
|
|
{
|
|
if (defaultDocks.contains(w))
|
|
{
|
|
w->show();
|
|
}
|
|
}
|
|
|
|
updateDockActionsChecked();
|
|
}
|
|
|
|
void MainWindow::resetToDefaultLayout()
|
|
{
|
|
hideAllDocks();
|
|
restoreDocks();
|
|
showDefaultDocks();
|
|
dashboardDock->raise();
|
|
|
|
// ugly workaround to set the default widths of functions and sidebar docks
|
|
// if anyone finds a way to do this cleaner that also works, feel free to change it!
|
|
auto restoreFunctionDock = qhelpers::forceWidth(functionsDock->widget(), 300);
|
|
auto restoreSidebarDock = qhelpers::forceWidth(sidebarDock->widget(), 300);
|
|
|
|
qApp->processEvents();
|
|
|
|
restoreFunctionDock.restoreWidth(functionsDock->widget());
|
|
restoreSidebarDock.restoreWidth(sidebarDock->widget());
|
|
|
|
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Disassembly);
|
|
}
|
|
|
|
void MainWindow::addOutput(const QString &msg)
|
|
{
|
|
consoleDock->addOutput(msg);
|
|
}
|
|
|
|
void MainWindow::addDebugOutput(const QString &msg)
|
|
{
|
|
printf("debug output: %s\n", msg.toLocal8Bit().constData());
|
|
consoleDock->addDebugOutput(msg);
|
|
}
|
|
|
|
void MainWindow::on_actionLock_triggered()
|
|
{
|
|
panelLock = !panelLock;
|
|
setPanelLock();
|
|
}
|
|
|
|
void MainWindow::on_actionLockUnlock_triggered()
|
|
{
|
|
if (ui->actionLockUnlock->isChecked())
|
|
{
|
|
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>())
|
|
{
|
|
dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
|
|
}
|
|
ui->actionLockUnlock->setIcon(QIcon(":/lock"));
|
|
}
|
|
else
|
|
{
|
|
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>())
|
|
{
|
|
dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
|
|
}
|
|
ui->actionLockUnlock->setIcon(QIcon(":/unlock"));
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionFunctionsRename_triggered()
|
|
{
|
|
RenameDialog *r = new RenameDialog(this);
|
|
// Get function based on click position
|
|
//r->setFunctionName(fcn_name);
|
|
r->open();
|
|
}
|
|
|
|
void MainWindow::on_actionDefault_triggered()
|
|
{
|
|
resetToDefaultLayout();
|
|
}
|
|
|
|
void MainWindow::on_actionNew_triggered()
|
|
{
|
|
on_actionOpen_triggered();
|
|
}
|
|
|
|
void MainWindow::on_actionSave_triggered()
|
|
{
|
|
saveProject();
|
|
}
|
|
|
|
void MainWindow::on_actionSaveAs_triggered()
|
|
{
|
|
saveProjectAs();
|
|
}
|
|
|
|
void MainWindow::on_actionRun_Script_triggered()
|
|
{
|
|
QFileDialog dialog(this);
|
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
|
dialog.setViewMode(QFileDialog::Detail);
|
|
dialog.setDirectory(QDir::home());
|
|
|
|
QString fileName;
|
|
fileName = dialog.getOpenFileName(this, tr("Select radare2 script"));
|
|
if (!fileName.length()) //cancel was pressed
|
|
return;
|
|
this->core->cmd(". " + fileName);
|
|
}
|
|
|
|
void MainWindow::on_actionOpen_triggered()
|
|
{
|
|
QProcess process(this);
|
|
process.setEnvironment(QProcess::systemEnvironment());
|
|
process.startDetached(qApp->applicationFilePath());
|
|
}
|
|
|
|
void MainWindow::toggleResponsive(bool maybe)
|
|
{
|
|
this->responsive = maybe;
|
|
// Save options in settings
|
|
QSettings settings;
|
|
settings.setValue("responsive", this->responsive);
|
|
}
|
|
|
|
void MainWindow::on_actionTabs_on_Top_triggered()
|
|
{
|
|
this->on_actionTabs_triggered();
|
|
}
|
|
|
|
void MainWindow::on_actionReset_settings_triggered()
|
|
{
|
|
QMessageBox::StandardButton ret =
|
|
(QMessageBox::StandardButton)QMessageBox::question(this, APPNAME,
|
|
tr("Do you really want to clear all settings?"),
|
|
QMessageBox::Ok | QMessageBox::Cancel);
|
|
if (ret == QMessageBox::Ok)
|
|
{
|
|
Config()->resetAll();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionQuit_triggered()
|
|
{
|
|
close();
|
|
}
|
|
|
|
void MainWindow::on_actionBackward_triggered()
|
|
{
|
|
Core()->seekPrev();
|
|
}
|
|
|
|
void MainWindow::on_actionForward_triggered()
|
|
{
|
|
Core()->seekNext();
|
|
}
|
|
|
|
void MainWindow::on_actionUndoSeek_triggered()
|
|
{
|
|
Core()->seekPrev();
|
|
}
|
|
|
|
void MainWindow::on_actionRedoSeek_triggered()
|
|
{
|
|
Core()->seekNext();
|
|
}
|
|
|
|
void MainWindow::on_actionDisasAdd_comment_triggered()
|
|
{
|
|
CommentsDialog *c = new CommentsDialog(this);
|
|
c->exec();
|
|
delete c;
|
|
}
|
|
|
|
void MainWindow::on_actionRefresh_contents_triggered()
|
|
{
|
|
refreshAll();
|
|
}
|
|
|
|
void MainWindow::on_actionPreferences_triggered()
|
|
{
|
|
auto dialog = new PreferencesDialog(this);
|
|
dialog->show();
|
|
}
|
|
|
|
void MainWindow::on_actionTabs_triggered()
|
|
{
|
|
tabsOnTop = !tabsOnTop;
|
|
setTabLocation();
|
|
}
|
|
|
|
void MainWindow::on_actionAbout_triggered()
|
|
{
|
|
AboutDialog *a = new AboutDialog(this);
|
|
a->open();
|
|
}
|
|
|
|
void MainWindow::on_actionRefresh_Panels_triggered()
|
|
{
|
|
this->refreshAll();
|
|
}
|
|
|
|
void MainWindow::on_actionAnalyze_triggered()
|
|
{
|
|
displayAnalysisOptionsDialog(-1, QList<QString>());
|
|
}
|
|
|
|
void MainWindow::on_actionImportPDB_triggered()
|
|
{
|
|
QFileDialog dialog(this);
|
|
dialog.setWindowTitle(tr("Select PDB file"));
|
|
dialog.setNameFilters({ tr("PDB file (*.pdb)"), tr("All files (*)") });
|
|
|
|
if (!dialog.exec())
|
|
{
|
|
return;
|
|
}
|
|
|
|
QString pdbFile = dialog.selectedFiles().first();
|
|
|
|
if (!pdbFile.isEmpty())
|
|
{
|
|
Core()->loadPDB(pdbFile);
|
|
addOutput(tr("%1 loaded.").arg(pdbFile));
|
|
}
|
|
}
|
|
|
|
void MainWindow::projectSaved(const QString &name)
|
|
{
|
|
addOutput(tr("Project saved: ") + name);
|
|
}
|
|
|
|
void MainWindow::addToDockWidgetList(QDockWidget *dockWidget) {
|
|
this->dockWidgets.push_back(dockWidget);
|
|
}
|
|
|
|
void MainWindow::addDockWidgetAction(QDockWidget *dockWidget, QAction *action) {
|
|
this->dockWidgetActions[action] = dockWidget;
|
|
}
|