Rewrite layout management code (#2172)

* Use QDockWidget::toggleViewAction instead of custom solution.
* Improve new dock placement.
This commit is contained in:
karliss 2020-05-22 14:49:34 +03:00 committed by GitHub
parent 8a3b51c291
commit 3545f059f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
87 changed files with 841 additions and 964 deletions

View File

@ -1,6 +1,7 @@
View Menu
==============================
Refresh contents
----------------------------------------
**Description:** In some cases, not all the displayed information on Cutter's widgets will be up-to-date, for example - after defining a new function from the integrated radare2 console. By refreshing the contents, Cutter will fetch the most up to date information from the session and will update the different views.
@ -12,9 +13,9 @@ Refresh contents
Reset to default layout
----------------------------------------
**Description:** Reset the current layout to the default layout provided by Cutter. Future additions will include custom and user-defined layouts to which you'll be able to reset.
**Description:** Reset the current layout to the default layout provided by Cutter.
**Steps:** View -> Reset Layout
**Steps:** View -> Reset to default layout
Reset to default settings
----------------------------------------
@ -24,7 +25,7 @@ Reset to default settings
Lock and Unlock panels
----------------------------------------
**Description:** Allow or disable locking the different widgets.
**Description:** Allow or disable moving and closing of different widgets. Uncheck this option to prevent accidentally modifying current layout.
**Steps:** View -> Unlock Panels
@ -63,4 +64,17 @@ Reset Zoom
**Steps:** View -> Zoom -> Reset
**Shortcut:** :kbd:`Ctrl` + :kbd:`=`
**Shortcut:** :kbd:`Ctrl` + :kbd:`=`
Save layout
----------------------------------------
**Description:** Save the current layout with a given name. A layout includes the set of currently opened widgets, their position, and some properties.
**Steps:** View -> Save Layout , enter a layout name in the dialog.
Layouts
----------------------------------------
**Description:** Load the settings from the selected layout into the current layout. Loading a layout will not cause it to automatically be modified. To do that you must use the `Save layout`_ command.
**Steps:** View -> Layouts -> layout name

View File

@ -421,7 +421,8 @@ SOURCES += \
widgets/ListDockWidget.cpp \
dialogs/MultitypeFileSaveDialog.cpp \
widgets/BoolToggleDelegate.cpp \
common/IOModesController.cpp
common/IOModesController.cpp \
common/SettingsUpgrade.cpp
GRAPHVIZ_SOURCES = \
widgets/GraphvizLayout.cpp
@ -568,7 +569,8 @@ HEADERS += \
widgets/AddressableItemList.h \
dialogs/MultitypeFileSaveDialog.h \
widgets/BoolToggleDelegate.h \
common/IOModesController.h
common/IOModesController.h \
common/SettingsUpgrade.h
GRAPHVIZ_HEADERS = widgets/GraphGridLayout.h

View File

@ -2,124 +2,13 @@
#include "CutterApplication.h"
#include "core/MainWindow.h"
#include "common/UpdateWorker.h"
#include "common/ColorThemeWorker.h"
#include "CutterConfig.h"
#include "common/CrashHandler.h"
#include "common/SettingsUpgrade.h"
#include <QJsonObject>
#include <QJsonArray>
/**
* @brief Migrate Settings used before Cutter 1.8
*
* @return whether any settings have been migrated
*/
static bool migrateSettingsPre18(QSettings &newSettings)
{
if(newSettings.value("settings_migrated", false).toBool()) {
return false;
}
QSettings oldSettings(QSettings::NativeFormat, QSettings::Scope::UserScope, "Cutter", "Cutter");
QStringList allKeys = oldSettings.allKeys();
if (allKeys.isEmpty()) {
return false;
}
qInfo() << "Migrating Settings from pre-1.8";
for (const QString &key : allKeys) {
newSettings.setValue(key, oldSettings.value(key));
}
oldSettings.clear();
QFile settingsFile(oldSettings.fileName());
settingsFile.remove();
newSettings.setValue("settings_migrated", true);
return true;
}
#define CUTTER_SETTINGS_VERSION_CURRENT 2
#define CUTTER_SETTINGS_VERSION_KEY "version"
/*
* How Settings migrations work:
*
* Every time settings are changed in a way that needs migration,
* CUTTER_SETTINGS_VERSION_CURRENT is raised by 1 and a function migrateSettingsToX
* is implemented and added to initializeSettings().
* This function takes care of migrating from EXACTLY version X-1 to X.
*/
static void migrateSettingsTo1(QSettings &settings) {
settings.remove("settings_migrated"); // now handled by version
settings.remove("updated_custom_themes"); // now handled by theme_version
}
static void migrateSettingsTo2(QSettings &settings) {
QStringList docks = settings.value("docks").toStringList(); // get current list of docks
// replace occurences of "PseudocodeWidget" with "DecompilerWidget"
settings.setValue("docks", docks.replaceInStrings("PseudocodeWidget", "DecompilerWidget"));
}
static void initializeSettings()
{
QSettings::setDefaultFormat(QSettings::IniFormat);
QSettings settings;
int settingsVersion = settings.value(CUTTER_SETTINGS_VERSION_KEY, 0).toInt();
if(settingsVersion == 0) {
migrateSettingsPre18(settings);
}
if(settings.allKeys().length() > 0) {
if (settingsVersion > CUTTER_SETTINGS_VERSION_CURRENT) {
qWarning() << "Settings have a higher version than current! Skipping migration.";
} else if(settingsVersion >= 0) {
for (int v = settingsVersion + 1; v <= CUTTER_SETTINGS_VERSION_CURRENT; v++) {
qInfo() << "Migrating Settings to Version" << v;
switch (v) {
case 1:
migrateSettingsTo1(settings); break;
case 2:
migrateSettingsTo2(settings);
default:
break;
}
}
}
}
settings.setValue(CUTTER_SETTINGS_VERSION_KEY, CUTTER_SETTINGS_VERSION_CURRENT);
}
#define THEME_VERSION_CURRENT 1
#define THEME_VERSION_KEY "theme_version"
static void removeObsoleteOptionsFromCustomThemes() {
const QStringList options = Core()->cmdj("ecj").object().keys()
<< ColorThemeWorker::cutterSpecificOptions;
for (auto theme : Core()->cmdList("eco*")) {
theme = theme.trimmed();
if (!ThemeWorker().isCustomTheme(theme)) {
continue;
}
QJsonObject updatedTheme;
auto sch = ThemeWorker().getTheme(theme).object();
for (const auto& key : sch.keys()) {
if (options.contains(key)) {
updatedTheme.insert(key, sch[key]);
}
}
ThemeWorker().save(QJsonDocument(updatedTheme), theme);
}
}
static void migrateThemes()
{
QSettings settings;
int themeVersion = settings.value(THEME_VERSION_KEY, 0).toInt();
if (themeVersion != THEME_VERSION_CURRENT) {
removeObsoleteOptionsFromCustomThemes();
settings.setValue(THEME_VERSION_KEY, THEME_VERSION_CURRENT);
}
}
/**
* @brief Attempt to connect to a parent console and configure outputs.
@ -183,7 +72,7 @@ int main(int argc, char *argv[])
QCoreApplication::setOrganizationName("RadareOrg");
QCoreApplication::setApplicationName("Cutter");
initializeSettings();
Cutter::initializeSettings();
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); // needed for QtWebEngine inside Plugins
#ifdef Q_OS_WIN
@ -195,7 +84,7 @@ int main(int argc, char *argv[])
CutterApplication a(argc, argv);
migrateThemes();
Cutter::migrateThemes();
if (Config()->getAutoUpdateEnabled()) {
#if CUTTER_UPDATE_WORKER_AVAILABLE

View File

@ -145,14 +145,14 @@ SizePolicyMinMax forceHeight(QWidget *widget, int height)
void SizePolicyMinMax::restoreWidth(QWidget *widget)
{
widget->setSizePolicy(sizePolicy);
widget->setSizePolicy(sizePolicy.horizontalPolicy(), widget->sizePolicy().verticalPolicy());
widget->setMinimumWidth(min);
widget->setMaximumWidth(max);
}
void SizePolicyMinMax::restoreHeight(QWidget *widget)
{
widget->setSizePolicy(sizePolicy);
widget->setSizePolicy(widget->sizePolicy().horizontalPolicy(), sizePolicy.verticalPolicy());
widget->setMinimumHeight(min);
widget->setMaximumHeight(max);
}

View File

@ -0,0 +1,168 @@
#include "SettingsUpgrade.h"
#include "common/ColorThemeWorker.h"
/**
* @brief Migrate Settings used before Cutter 1.8
*
* @return whether any settings have been migrated
*/
static bool migrateSettingsPre18(QSettings &newSettings)
{
if(newSettings.value("settings_migrated", false).toBool()) {
return false;
}
QSettings oldSettings(QSettings::NativeFormat, QSettings::Scope::UserScope, "Cutter", "Cutter");
QStringList allKeys = oldSettings.allKeys();
if (allKeys.isEmpty()) {
return false;
}
qInfo() << "Migrating Settings from pre-1.8";
for (const QString &key : allKeys) {
newSettings.setValue(key, oldSettings.value(key));
}
oldSettings.clear();
QFile settingsFile(oldSettings.fileName());
settingsFile.remove();
newSettings.setValue("settings_migrated", true);
return true;
}
#define CUTTER_SETTINGS_VERSION_CURRENT 3
#define CUTTER_SETTINGS_VERSION_KEY "version"
/*
* How Settings migrations work:
*
* Every time settings are changed in a way that needs migration,
* CUTTER_SETTINGS_VERSION_CURRENT is raised by 1 and a function migrateSettingsToX
* is implemented and added to initializeSettings().
* This function takes care of migrating from EXACTLY version X-1 to X.
*/
static void migrateSettingsTo1(QSettings &settings) {
settings.remove("settings_migrated"); // now handled by version
settings.remove("updated_custom_themes"); // now handled by theme_version
}
static void migrateSettingsTo2(QSettings &settings) {
QStringList docks = settings.value("docks").toStringList(); // get current list of docks
// replace occurences of "PseudocodeWidget" with "DecompilerWidget"
settings.setValue("docks", docks.replaceInStrings("PseudocodeWidget", "DecompilerWidget"));
}
static void migrateSettingsTo3(QSettings &settings) {
auto defaultGeometry = settings.value("geometry").toByteArray();
auto defaultState = settings.value("state").toByteArray();
auto debugGeometry = settings.value("debug.geometry").toByteArray();
auto debugState = settings.value("debug.state").toByteArray();
const auto docks = settings.value("docks", QStringList()).toStringList();
auto unsyncList = settings.value("unsync", QStringList()).toStringList();
#if QT_VERSION < QT_VERSION_CHECK(5,14,0)
QSet<QString> unsyncDocks = unsyncList.toSet();
#else
QSet<QString> unsyncDocks(unsyncList.begin(), unsyncList.end());
#endif
QVariantMap viewProperties;
for (auto &dock : docks) {
QVariantMap properties;
bool synchronized = true;
if (unsyncDocks.contains(dock)) {
synchronized = false;
}
properties.insert("synchronized", synchronized);
viewProperties.insert(dock, properties);
}
settings.beginWriteArray("layouts", 2);
settings.setArrayIndex(0);
settings.setValue("name", "Default");
settings.setValue("geometry", defaultGeometry);
settings.setValue("state", defaultState);
settings.setValue("docks", viewProperties);
settings.setArrayIndex(1);
settings.setValue("name", "Debug");
settings.setValue("geometry", debugGeometry);
settings.setValue("state", debugState);
settings.setValue("docks", viewProperties);
settings.endArray();
settings.remove("pos"); // Pos and size already stored within geometry
settings.remove("size");
// keep geometry but with slightly different usecase
settings.remove("state");
settings.remove("debug.geometry");
settings.remove("debug.state");
settings.remove("docks");
settings.remove("unsync");
}
void Cutter::initializeSettings()
{
QSettings::setDefaultFormat(QSettings::IniFormat);
QSettings settings;
int settingsVersion = settings.value(CUTTER_SETTINGS_VERSION_KEY, 0).toInt();
if(settingsVersion == 0) {
migrateSettingsPre18(settings);
}
if(settings.allKeys().length() > 0) {
if (settingsVersion > CUTTER_SETTINGS_VERSION_CURRENT) {
qWarning() << "Settings have a higher version than current! Skipping migration.";
} else if(settingsVersion >= 0) {
for (int v = settingsVersion + 1; v <= CUTTER_SETTINGS_VERSION_CURRENT; v++) {
qInfo() << "Migrating Settings to Version" << v;
switch (v) {
case 1:
migrateSettingsTo1(settings); break;
case 2:
migrateSettingsTo2(settings); break;
case 3:
migrateSettingsTo3(settings); break;
default:
break;
}
}
}
}
settings.setValue(CUTTER_SETTINGS_VERSION_KEY, CUTTER_SETTINGS_VERSION_CURRENT);
}
#define THEME_VERSION_CURRENT 1
#define THEME_VERSION_KEY "theme_version"
static void removeObsoleteOptionsFromCustomThemes() {
const QStringList options = Core()->cmdj("ecj").object().keys()
<< ColorThemeWorker::cutterSpecificOptions;
for (auto theme : Core()->cmdList("eco*")) {
theme = theme.trimmed();
if (!ThemeWorker().isCustomTheme(theme)) {
continue;
}
QJsonObject updatedTheme;
auto sch = ThemeWorker().getTheme(theme).object();
for (const auto& key : sch.keys()) {
if (options.contains(key)) {
updatedTheme.insert(key, sch[key]);
}
}
ThemeWorker().save(QJsonDocument(updatedTheme), theme);
}
}
void Cutter::migrateThemes()
{
QSettings settings;
int themeVersion = settings.value(THEME_VERSION_KEY, 0).toInt();
if (themeVersion != THEME_VERSION_CURRENT) {
removeObsoleteOptionsFromCustomThemes();
settings.setValue(THEME_VERSION_KEY, THEME_VERSION_CURRENT);
}
}

View File

@ -0,0 +1,12 @@
#ifndef COMMON_SETTINGS_UPGRADE_H
#define COMMON_SETTINGS_UPGRADE_H
#include <QSettings>
#include <core/Cutter.h>
namespace Cutter {
void initializeSettings();
void migrateThemes();
}
#endif // COMMON_SETTINGS_UPGRADE_H

View File

@ -61,5 +61,12 @@ inline QString RHexString(RVA size)
#define CUTTER_EXPORT Q_DECL_IMPORT
#endif
#if defined(__has_cpp_attribute) && __has_cpp_attribute(deprecated)
#define CUTTER_DEPRECATED(msg) [[deprecated(msg)]]
#else
#define CUTTER_DEPRECATED(msg)
#endif
#endif // CUTTERCORE_H

View File

@ -91,6 +91,7 @@
#include <QSysInfo>
#include <QJsonObject>
#include <QJsonArray>
#include <QInputDialog>
#include <QScrollBar>
#include <QSettings>
@ -111,7 +112,14 @@
#include <QGraphicsView>
template<class T>
T* getNewInstance(MainWindow *m, QAction *a) { return new T(m, a); }
T *getNewInstance(MainWindow *m) { return new T(m); }
static const QString LAYOUT_DEFAULT = "Default";
static const QString LAYOUT_DEBUG = "Debug";
static bool isBuiltinLayoutName(const QString &name) {
return name == LAYOUT_DEFAULT || name == LAYOUT_DEBUG;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
@ -147,7 +155,8 @@ void MainWindow::initUI()
connect(Core(), &CutterCore::ioCacheChanged, ui->actionCommitChanges, &QAction::setEnabled);
widgetTypeToConstructorMap.insert(GraphWidget::getWidgetType(), getNewInstance<GraphWidget>);
widgetTypeToConstructorMap.insert(DisassemblyWidget::getWidgetType(), getNewInstance<DisassemblyWidget>);
widgetTypeToConstructorMap.insert(DisassemblyWidget::getWidgetType(),
getNewInstance<DisassemblyWidget>);
widgetTypeToConstructorMap.insert(HexdumpWidget::getWidgetType(), getNewInstance<HexdumpWidget>);
initToolBar();
@ -202,6 +211,8 @@ void MainWindow::initUI()
initBackForwardMenu();
connect(ui->actionSaveLayout, &QAction::triggered, this, &MainWindow::saveNamedLayout);
/* Setup plugins interfaces */
for (auto &plugin : Plugins()->getPlugins()) {
plugin->setupInterface(this);
@ -211,7 +222,8 @@ void MainWindow::initUI()
ui->actionGrouped_dock_dragging->setVisible(false);
#endif
initLayout();
enableDebugWidgetsMenu(false);
readSettings();
}
void MainWindow::initToolBar()
@ -296,85 +308,97 @@ void MainWindow::initToolBar()
void MainWindow::initDocks()
{
dockWidgets.reserve(20);
decompilerDock = new DecompilerWidget(this, ui->actionDecompiler);
consoleDock = new ConsoleWidget(this, ui->actionConsole);
decompilerDock = new DecompilerWidget(this);
consoleDock = new ConsoleWidget(this);
overviewDock = new OverviewWidget(this, ui->actionOverview);
overviewDock = new OverviewWidget(this);
overviewDock->hide();
actionOverview = overviewDock->toggleViewAction();
connect(overviewDock, &OverviewWidget::isAvailableChanged, this, [this](bool isAvailable) {
ui->actionOverview->setEnabled(isAvailable);
});
ui->actionOverview->setEnabled(overviewDock->getIsAvailable());
connect(ui->actionOverview, &QAction::toggled, [this](bool checked) {
if (checked) {
overviewDock->show();
} else {
overviewDock->hide();
}
actionOverview->setEnabled(isAvailable);
});
actionOverview->setEnabled(overviewDock->getIsAvailable());
actionOverview->setChecked(overviewDock->getUserOpened());
ui->actionOverview->setChecked(overviewDock->getUserOpened());
sectionsDock = new SectionsWidget(this, ui->actionSections);
segmentsDock = new SegmentsWidget(this, ui->actionSegments);
entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints);
functionsDock = new FunctionsWidget(this, ui->actionFunctions);
importsDock = new ImportsWidget(this, ui->actionImports);
exportsDock = new ExportsWidget(this, ui->actionExports);
headersDock = new HeadersWidget(this, ui->actionHeaders);
zignaturesDock = new ZignaturesWidget(this, ui->actionZignatures);
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);
stackDock = new StackWidget(this, ui->actionStack);
threadsDock = new ThreadsWidget(this, ui->actionThreads);
processesDock = new ProcessesWidget(this, ui->actionProcesses);
backtraceDock = new BacktraceWidget(this, ui->actionBacktrace);
registersDock = new RegistersWidget(this, ui->actionRegisters);
memoryMapDock = new MemoryMapWidget(this, ui->actionMemoryMap);
breakpointDock = new BreakpointWidget(this, ui->actionBreakpoint);
registerRefsDock = new RegisterRefsWidget(this, ui->actionRegisterRefs);
dashboardDock = new Dashboard(this, ui->actionDashboard);
sdbDock = new SdbWidget(this, ui->actionSDBBrowser);
classesDock = new ClassesWidget(this, ui->actionClasses);
resourcesDock = new ResourcesWidget(this, ui->actionResources);
vTablesDock = new VTablesWidget(this, ui->actionVTables);
dashboardDock = new Dashboard(this);
functionsDock = new FunctionsWidget(this);
typesDock = new TypesWidget(this);
searchDock = new SearchWidget(this);
commentsDock = new CommentsWidget(this);
stringsDock = new StringsWidget(this);
QSettings s;
QStringList docks = s.value("docks", QStringList {
DisassemblyWidget::getWidgetType(),
GraphWidget::getWidgetType(),
HexdumpWidget::getWidgetType()
}).toStringList();
QList<CutterDockWidget *> debugDocks = {
stackDock = new StackWidget(this),
threadsDock = new ThreadsWidget(this),
processesDock = new ProcessesWidget(this),
backtraceDock = new BacktraceWidget(this),
registersDock = new RegistersWidget(this),
memoryMapDock = new MemoryMapWidget(this),
breakpointDock = new BreakpointWidget(this),
registerRefsDock = new RegisterRefsWidget(this)
};
// Restore all extra widgets
QString className;
for (const auto &it : docks) {
if (std::none_of(dockWidgets.constBegin(), dockWidgets.constEnd(),
[&it](QDockWidget * w) { return w->objectName() == it; })) {
className = it.split(';').at(0);
if (widgetTypeToConstructorMap.contains(className)) {
auto widget = widgetTypeToConstructorMap[className](this, nullptr);
widget->setObjectName(it);
addExtraWidget(widget);
QList<CutterDockWidget *> infoDocks = {
classesDock = new ClassesWidget(this),
entrypointDock = new EntrypointWidget(this),
exportsDock = new ExportsWidget(this),
flagsDock = new FlagsWidget(this),
headersDock = new HeadersWidget(this),
importsDock = new ImportsWidget(this),
relocsDock = new RelocsWidget(this),
resourcesDock = new ResourcesWidget(this),
sdbDock = new SdbWidget(this),
sectionsDock = new SectionsWidget(this),
segmentsDock = new SegmentsWidget(this),
symbolsDock = new SymbolsWidget(this),
vTablesDock = new VTablesWidget(this),
zignaturesDock = new ZignaturesWidget(this)
};
auto makeActionList = [this](QList<CutterDockWidget *> docks) {
QList<QAction *> result;
for (auto dock : docks) {
if (dock != nullptr) {
result.push_back(dock->toggleViewAction());
} else {
auto separator = new QAction(this);
separator->setSeparator(true);
result.push_back(separator);
}
}
return result;
};
QList<CutterDockWidget *> windowDocks = {
dashboardDock,
nullptr,
functionsDock,
decompilerDock,
overviewDock,
nullptr,
searchDock,
stringsDock,
typesDock,
nullptr,
};
ui->menuWindows->insertActions(ui->actionExtraDisassembly, makeActionList(windowDocks));
QList<CutterDockWidget *> windowDocks2 = {
consoleDock,
commentsDock,
nullptr,
};
ui->menuWindows->addActions(makeActionList(windowDocks2));
ui->menuAddInfoWidgets->addActions(makeActionList(infoDocks));
ui->menuAddDebugWidgets->addActions(makeActionList(debugDocks));
auto uniqueDocks = windowDocks + windowDocks2 + infoDocks + debugDocks;
for (auto dock : uniqueDocks) {
if (dock) { // ignore nullptr used as separators
addWidget(dock);
}
}
}
void MainWindow::initLayout()
{
// Set up dock widgets default layout
enableDebugWidgetsMenu(false);
// Restore saved settings
readSettingsOrDefault();
initCorners();
}
void MainWindow::toggleOverview(bool visibility, GraphWidget *targetGraph)
{
if (!overviewDock) {
@ -393,29 +417,29 @@ void MainWindow::updateTasksIndicator()
void MainWindow::addExtraGraph()
{
auto *extraDock = new GraphWidget(this, nullptr);
auto *extraDock = new GraphWidget(this);
addExtraWidget(extraDock);
}
void MainWindow::addExtraHexdump()
{
auto *extraDock = new HexdumpWidget(this, nullptr);
auto *extraDock = new HexdumpWidget(this);
addExtraWidget(extraDock);
}
void MainWindow::addExtraDisassembly()
{
auto *extraDock = new DisassemblyWidget(this, nullptr);
auto *extraDock = new DisassemblyWidget(this);
addExtraWidget(extraDock);
}
void MainWindow::addExtraWidget(CutterDockWidget *extraDock)
{
extraDock->setTransient(true);
addDockWidget(Qt::TopDockWidgetArea, extraDock, Qt::Orientation::Horizontal);
auto restoreExtraDock = qhelpers::forceWidth(extraDock->widget(), 600);
qApp->processEvents();
restoreExtraDock.restoreWidth(extraDock->widget());
dockOnMainArea(extraDock);
addWidget(extraDock);
extraDock->show();
extraDock->raise();
}
QMenu *MainWindow::getMenuByType(MenuType type)
@ -440,14 +464,12 @@ QMenu *MainWindow::getMenuByType(MenuType type)
}
}
void MainWindow::addPluginDockWidget(QDockWidget *dockWidget, QAction *action)
void MainWindow::addPluginDockWidget(CutterDockWidget *dockWidget)
{
addDockWidget(Qt::TopDockWidgetArea, dockWidget);
dockWidget->addAction(action);
addWidget(dockWidget);
ui->menuPlugins->addAction(action);
ui->menuPlugins->addAction(dockWidget->toggleViewAction());
addDockWidget(Qt::DockWidgetArea::TopDockWidgetArea, dockWidget);
updateDockActionChecked(action);
pluginDocks.push_back(dockWidget);
}
void MainWindow::addMenuFileAction(QAction *action)
@ -546,21 +568,21 @@ void MainWindow::finalizeOpen()
core->getOpcodes();
core->updateSeek();
refreshAll();
// Add fortune message
core->message("\n" + core->cmdRaw("fo"));
showMaximized();
Config()->adjustColorThemeDarkness();
QSettings s;
QStringList unsync = s.value("unsync").toStringList();
for (auto it : dockWidgets) {
auto w = qobject_cast<MemoryDockWidget*>(it);
if (w) {
w->getSeekable()->setSynchronization(!unsync.contains(it->objectName()));
}
QSettings settings;
auto geometry = settings.value("geometry").toByteArray();
if (!geometry.isEmpty()) {
restoreGeometry(geometry);
show();
} else {
showMaximized();
}
Config()->adjustColorThemeDarkness();
setViewLayout(getViewLayout(LAYOUT_DEFAULT));
// Set focus to disasm or graph widget
// Use for loop to cover cases when main disasm/graph
@ -577,7 +599,7 @@ void MainWindow::finalizeOpen()
bool graphContainsFunc = false;
for (auto dockWidget : dockWidgets) {
const QString className = dockWidget->metaObject()->className();
auto graphWidget = qobject_cast<GraphWidget*>(dockWidget);
auto graphWidget = qobject_cast<GraphWidget *>(dockWidget);
if (graphWidget && !dockWidget->visibleRegion().isNull()) {
graphContainsFunc = !graphWidget->getGraphView()->getBlocks().empty();
if (graphContainsFunc) {
@ -585,7 +607,7 @@ void MainWindow::finalizeOpen()
break;
}
}
auto disasmWidget = qobject_cast<DisassemblyWidget*>(dockWidget);
auto disasmWidget = qobject_cast<DisassemblyWidget *>(dockWidget);
if (disasmWidget && !dockWidget->visibleRegion().isNull()) {
if (!graphContainsFunc) {
disasmWidget->setFocus();
@ -671,41 +693,18 @@ void MainWindow::paintEvent(QPaintEvent *event)
QMainWindow::paintEvent(event);
/*
* Dirty hack
* Just to adjust the width of Functions Widget to fixed size
* After everything is drawn, safely make it Preferred size policy
* So that user can change the widget size with the mouse
* Just to adjust the width of Functions Widget to fixed size.
* After everything is drawn, restore the max width limit.
*/
if (functionsDock) {
functionsDock->changeSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
if (functionsDock && functionDockWidthToRestore) {
functionsDock->setMaximumWidth(functionDockWidthToRestore);
functionDockWidthToRestore = 0;
}
}
void MainWindow::readSettingsOrDefault()
void MainWindow::readSettings()
{
QSettings settings;
QByteArray geo = settings.value("geometry", QByteArray()).toByteArray();
QByteArray state = settings.value("state", QByteArray()).toByteArray();
/*
* Check if saved settings exist
* If not, then read the default layout
*/
if (!geo.length() || !state.length()) {
resetToDefaultLayout();
return;
}
hideAllDocks();
restoreGeometry(geo);
restoreState(state);
// make sure all DockWidgets are part of the MainWindow
// also show them, so newly installed plugin widgets are shown right away
for (auto dockWidget : dockWidgets) {
if (dockWidgetArea(dockWidget) == Qt::DockWidgetArea::NoDockWidgetArea &&
!isDebugWidget(dockWidget)) {
addDockWidget(Qt::DockWidgetArea::TopDockWidgetArea, dockWidget);
dockWidget->show();
}
}
responsive = settings.value("responsive").toBool();
panelLock = settings.value("panelLock").toBool();
@ -716,59 +715,22 @@ void MainWindow::readSettingsOrDefault()
ui->actionGrouped_dock_dragging->setChecked(dockGroupedDragging);
on_actionGrouped_dock_dragging_triggered(dockGroupedDragging);
QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
QSize size = settings.value("size", QSize(400, 400)).toSize();
resize(size);
move(pos);
updateDockActionsChecked();
loadLayouts(settings);
}
void MainWindow::saveSettings()
{
QSettings settings;
QStringList docks;
QStringList unsync;
for (const auto &it : dockWidgets) {
docks.append(it->objectName());
auto memoryDockWidget = qobject_cast<MemoryDockWidget*>(it);
if (memoryDockWidget && !memoryDockWidget->getSeekable()->isSynchronized()) {
unsync.append(it->objectName());
}
}
settings.setValue("docks", docks);
settings.setValue("unsync", unsync);
settings.setValue("geometry", saveGeometry());
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.setValue("state", saveState());
settings.setValue("panelLock", panelLock);
settings.setValue("tabsOnTop", tabsOnTop);
settings.setValue("docksGroupedDragging", ui->actionGrouped_dock_dragging->isChecked());
settings.setValue("geometry", saveGeometry());
layouts[Core()->currentlyDebugging ? LAYOUT_DEBUG : LAYOUT_DEFAULT] = getViewLayout();
saveLayouts(settings);
}
void MainWindow::readDebugSettings()
{
QSettings settings;
QByteArray geo = settings.value("debug.geometry", QByteArray()).toByteArray();
restoreGeometry(geo);
QByteArray state = settings.value("debug.state", QByteArray()).toByteArray();
restoreState(state);
QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
QSize size = settings.value("size", QSize(400, 400)).toSize();
resize(size);
move(pos);
updateDockActionsChecked();
}
void MainWindow::saveDebugSettings()
{
QSettings settings;
settings.setValue("debug.geometry", saveGeometry());
settings.setValue("debug.state", saveState());
settings.setValue("size", size());
settings.setValue("pos", pos());
}
void MainWindow::setPanelLock()
{
@ -819,12 +781,19 @@ void MainWindow::lockUnlock_Docks(bool what)
void MainWindow::restoreDocks()
{
// In the upper half the functions are the first widget
addDockWidget(Qt::TopDockWidgetArea, functionsDock);
addDockWidget(Qt::TopDockWidgetArea, overviewDock);
// Function | Dashboard
// Initial structure
// func | main area | debug
// |___________|
// | console |
addDockWidget(Qt::LeftDockWidgetArea, functionsDock);
splitDockWidget(functionsDock, dashboardDock, Qt::Horizontal);
splitDockWidget(dashboardDock, stackDock, Qt::Horizontal);
splitDockWidget(dashboardDock, consoleDock, Qt::Vertical);
// overview bellow func
splitDockWidget(functionsDock, overviewDock, Qt::Vertical);
// main area
tabifyDockWidget(dashboardDock, decompilerDock);
tabifyDockWidget(dashboardDock, entrypointDock);
tabifyDockWidget(dashboardDock, flagsDock);
@ -846,46 +815,24 @@ void MainWindow::restoreDocks()
tabifyDockWidget(dashboardDock, registerRefsDock);
for (const auto &it : dockWidgets) {
// Check whether or not current widgets is graph, hexdump or disasm
if (qobject_cast<GraphWidget*>(it) ||
qobject_cast<HexdumpWidget*>(it) ||
qobject_cast<DisassemblyWidget*>(it)) {
if (isExtraMemoryWidget(it)) {
tabifyDockWidget(dashboardDock, it);
}
}
splitDockWidget(functionsDock, overviewDock, Qt::Vertical);
// In the lower half the console is the first widget
addDockWidget(Qt::BottomDockWidgetArea, consoleDock);
// Console | Sections
// Console | Sections/segments/comments
splitDockWidget(consoleDock, sectionsDock, Qt::Horizontal);
splitDockWidget(consoleDock, segmentsDock, Qt::Horizontal);
tabifyDockWidget(sectionsDock, segmentsDock);
tabifyDockWidget(sectionsDock, commentsDock);
// Add Stack, Registers, Threads and Backtrace vertically stacked
addDockWidget(Qt::TopDockWidgetArea, stackDock);
splitDockWidget(stackDock, registersDock, Qt::Vertical);
tabifyDockWidget(stackDock, backtraceDock);
tabifyDockWidget(backtraceDock, threadsDock);
tabifyDockWidget(threadsDock, processesDock);
updateDockActionsChecked();
}
void MainWindow::hideAllDocks()
{
for (auto w : dockWidgets) {
removeDockWidget(w);
}
}
void MainWindow::updateDockActionsChecked()
{
for (auto i = dockWidgetsOfAction.constBegin(); i != dockWidgetsOfAction.constEnd(); i++) {
updateDockActionChecked(i.key());
for (auto dock : pluginDocks) {
dockOnMainArea(dock);
}
}
@ -901,6 +848,13 @@ bool MainWindow::isDebugWidget(QDockWidget *dock) const
dock == registerRefsDock;
}
bool MainWindow::isExtraMemoryWidget(QDockWidget *dock) const
{
return qobject_cast<GraphWidget*>(dock) ||
qobject_cast<HexdumpWidget*>(dock) ||
qobject_cast<DisassemblyWidget*>(dock);
}
MemoryWidgetType MainWindow::getMemoryWidgetTypeToRestore()
{
if (lastSyncMemoryWidget) {
@ -963,7 +917,7 @@ QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address)
for (auto &dock : dockWidgets) {
if (auto memoryWidget = qobject_cast<MemoryDockWidget *>(dock)) {
QAction *action = new QAction(memoryWidget->windowTitle(), menu);
connect(action, &QAction::triggered, this, [this, memoryWidget, address](){
connect(action, &QAction::triggered, this, [this, memoryWidget, address]() {
memoryWidget->getSeekable()->seek(address);
memoryWidget->raiseMemoryWidget();
});
@ -973,7 +927,7 @@ QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address)
menu->addSeparator();
auto createAddNewWidgetAction = [this, menu, address](QString label, MemoryWidgetType type) {
QAction *action = new QAction(label, menu);
connect(action, &QAction::triggered, this, [this, address, type](){
connect(action, &QAction::triggered, this, [this, address, type]() {
addNewMemoryWidget(type, address, false);
});
menu->addAction(action);
@ -1023,18 +977,6 @@ MemoryDockWidget *MainWindow::addNewMemoryWidget(MemoryWidgetType type, RVA addr
return memoryWidget;
}
void MainWindow::initCorners()
{
// TODO: Allow the user to select this option visually in the GUI settings
// Adjust the DockWidget areas
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
}
void MainWindow::initBackForwardMenu()
{
auto prepareButtonMenu = [this](QAction *action) -> QMenu* {
@ -1135,21 +1077,43 @@ void MainWindow::updateHistoryMenu(QMenu *menu, bool redo)
}
void MainWindow::addWidget(QDockWidget* widget)
void MainWindow::updateLayoutsMenu()
{
ui->menuLayouts->clear();
for (auto it = layouts.begin(), end = layouts.end(); it != end; ++it) {
QString name = it.key();
if (isBuiltinLayoutName(name)) {
continue;
}
auto action = new QAction(it.key(), ui->menuLayouts);
connect(action, &QAction::triggered, this, [this, name]() {
setViewLayout(getViewLayout(name));
});
ui->menuLayouts->addAction(action);
}
}
void MainWindow::saveNamedLayout()
{
bool ok = false;
QString name;
while (name.isEmpty() || isBuiltinLayoutName(name)) {
if (ok) {
QMessageBox::warning(this, tr("Save layout error"), tr("'%1' is not a valid name.").arg(name));
}
name = QInputDialog::getText(this, tr("Save layout"), tr("Enter name"), QLineEdit::Normal, {}, &ok);
if (!ok) {
return;
}
}
layouts[name] = getViewLayout();
updateLayoutsMenu();
saveSettings();
}
void MainWindow::addWidget(CutterDockWidget *widget)
{
dockWidgets.push_back(widget);
for (auto action : widget->actions()) {
dockWidgetsOfAction.insert(action, widget);
connect(qobject_cast<CutterDockWidget*>(widget), &CutterDockWidget::closed,
this, [this]() {
QDockWidget *widget = qobject_cast<QDockWidget*>(sender());
dockWidgets.removeOne(widget);
for (auto action : widget->actions()) {
dockWidgetsOfAction.remove(action, widget);
}
updateDockActionsChecked();
});
}
}
void MainWindow::addMemoryDockWidget(MemoryDockWidget *widget)
@ -1161,9 +1125,10 @@ void MainWindow::addMemoryDockWidget(MemoryDockWidget *widget)
});
}
void MainWindow::removeWidget(QDockWidget *widget)
void MainWindow::removeWidget(CutterDockWidget *widget)
{
dockWidgets.removeAll(widget);
pluginDocks.removeAll(widget);
if (lastSyncMemoryWidget == widget) {
lastSyncMemoryWidget = nullptr;
}
@ -1172,15 +1137,6 @@ void MainWindow::removeWidget(QDockWidget *widget)
}
}
void MainWindow::updateDockActionChecked(QAction *action)
{
auto actions = dockWidgetsOfAction.values(action);
action->setChecked(!std::accumulate(actions.begin(), actions.end(), false,
[](bool a, QDockWidget* w) -> bool {
return a || w->isHidden();
}));
}
void MainWindow::showZenDocks()
{
const QList<QDockWidget *> zenDocks = { functionsDock,
@ -1189,18 +1145,15 @@ void MainWindow::showZenDocks()
searchDock,
importsDock
};
int width = functionsDock->maximumWidth();
functionDockWidthToRestore = functionsDock->maximumWidth();
functionsDock->setMaximumWidth(200);
for (auto w : dockWidgets) {
if (zenDocks.contains(w) ||
qobject_cast<GraphWidget*>(w) ||
qobject_cast<HexdumpWidget*>(w) ||
qobject_cast<DisassemblyWidget*>(w)) {
isExtraMemoryWidget(w)) {
w->show();
}
}
functionsDock->setMaximumWidth(width);
updateDockActionsChecked();
dashboardDock->raise();
}
void MainWindow::showDebugDocks()
@ -1215,18 +1168,54 @@ void MainWindow::showDebugDocks()
memoryMapDock,
breakpointDock
};
int width = functionsDock->maximumWidth();
functionDockWidthToRestore = functionsDock->maximumWidth();
functionsDock->setMaximumWidth(200);
auto registerWidth = qhelpers::forceWidth(registersDock, std::min(500, this->width() / 4));
auto registerHeight = qhelpers::forceHeight(registersDock, std::max(100, height() / 2));
QDockWidget *widgetToFocus = nullptr;
for (auto w : dockWidgets) {
if (debugDocks.contains(w) ||
qobject_cast<GraphWidget*>(w) ||
qobject_cast<HexdumpWidget*>(w) ||
qobject_cast<DisassemblyWidget*>(w)) {
isExtraMemoryWidget(w)) {
w->show();
}
if (qobject_cast<DisassemblyWidget*>(w)) {
widgetToFocus = w;
}
}
registerHeight.restoreHeight(registersDock);
registerWidth.restoreWidth(registersDock);
if (widgetToFocus) {
widgetToFocus->raise();
}
}
void MainWindow::dockOnMainArea(QDockWidget *widget)
{
QDockWidget* best = nullptr;
float bestScore = 1;
// choose best existing area for placing the new widget
for (auto dock : dockWidgets) {
if (dock->isHidden() || dock == widget ||
dock->isFloating() || // tabifying onto floating dock using code doesn't work well
dock->parentWidget() != this) { // floating group isn't considered floating
continue;
}
float newScore = 0;
if (isExtraMemoryWidget(dock)) {
newScore += 10000000; // prefer existing disssasembly and graph widgets
}
newScore += dock->width() * dock->height(); // the bigger the better
if (newScore > bestScore) {
bestScore = newScore;
best = dock;
}
}
if (best) {
tabifyDockWidget(best, widget);
} else {
addDockWidget(Qt::TopDockWidgetArea, widget, Qt::Orientation::Horizontal);
}
functionsDock->setMaximumWidth(width);
updateDockActionsChecked();
}
void MainWindow::enableDebugWidgetsMenu(bool enable)
@ -1239,57 +1228,144 @@ void MainWindow::enableDebugWidgetsMenu(bool enable)
}
}
void MainWindow::resetToDefaultLayout()
CutterLayout MainWindow::getViewLayout()
{
hideAllDocks();
restoreDocks();
showZenDocks();
dashboardDock->raise();
}
CutterLayout layout;
layout.geometry = saveGeometry();
layout.state = saveState();
void MainWindow::resetToDebugLayout()
{
MemoryWidgetType memType = getMemoryWidgetTypeToRestore();
hideAllDocks();
restoreDocks();
showDebugDocks();
showMemoryWidget(memType);
auto restoreStackDock = qhelpers::forceWidth(stackDock->widget(), 400);
qApp->processEvents();
restoreStackDock.restoreWidth(stackDock->widget());
}
void MainWindow::restoreDebugLayout()
{
MemoryWidgetType memType = getMemoryWidgetTypeToRestore();
bool isMaxim = isMaximized();
hideAllDocks();
restoreDocks();
showDebugDocks();
readDebugSettings();
showMemoryWidget(memType);
if (isMaxim) {
showMaximized();
} else {
showNormal();
for (auto dock : dockWidgets) {
QVariantMap properties;
if (auto cutterDock = qobject_cast<CutterDockWidget *>(dock)) {
properties = cutterDock->serializeViewProprties();
}
layout.viewProperties.insert(dock->objectName(), std::move(properties));
}
return layout;
}
void MainWindow::resetDockWidgetList()
CutterLayout MainWindow::getViewLayout(const QString &name)
{
QStringList isLeft;
QList<QWidget*> toClose;
for (auto it : dockWidgets) {
if (isLeft.contains(it->metaObject()->className())) {
toClose.append(it);
} else if (QRegularExpression("\\A(?:\\w+ \\d+)\\z").match(it->objectName()).hasMatch()) {
isLeft.append(it->metaObject()->className());
auto it = layouts.find(name);
if (it != layouts.end()) {
return *it;
}
return {};
}
void MainWindow::setViewLayout(const CutterLayout &layout)
{
bool isDefault = layout.state.isEmpty() || layout.geometry.isEmpty();
bool isDebug = Core()->currentlyDebugging;
// make a copy to avoid iterating over container from which items are being removed
auto widgetsToClose = dockWidgets;
for (auto dock : widgetsToClose) {
dock->hide();
dock->close();
dock->setFloating(false); // tabifyDockWidget doesn't work if dock is floating
removeDockWidget(dock);
}
QStringList docksToCreate;
if (isDefault) {
docksToCreate = QStringList {
DisassemblyWidget::getWidgetType(),
GraphWidget::getWidgetType(),
HexdumpWidget::getWidgetType()
};
} else {
docksToCreate = layout.viewProperties.keys();
}
for (const auto &it : docksToCreate) {
if (std::none_of(dockWidgets.constBegin(), dockWidgets.constEnd(),
[&it](QDockWidget * w) { return w->objectName() == it; })) {
auto className = it.split(';').at(0);
if (widgetTypeToConstructorMap.contains(className)) {
auto widget = widgetTypeToConstructorMap[className](this);
widget->setObjectName(it);
addExtraWidget(widget);
}
}
}
for (auto it : toClose) {
it->close();
restoreDocks();
QList<QDockWidget *> newDocks;
for (auto dock : dockWidgets) {
auto properties = layout.viewProperties.find(dock->objectName());
if (properties != layout.viewProperties.end()) {
dock->deserializeViewProperties(*properties);
} else {
dock->deserializeViewProperties({}); // call with empty properties to reset the widget
newDocks.push_back(dock);
}
}
if (!isDefault) {
restoreState(layout.state);
for (auto dock : newDocks) {
dock->hide(); // hide to prevent dockOnMainArea putting them on each other
}
for (auto dock : newDocks) {
dockOnMainArea(dock);
// Show any new docks by default.
// Showing new builtin docks helps discovering features added in latest release.
// Installing a new plugin hints that usre will likely want to use it.
dock->show();
}
} else {
if (isDebug) {
showDebugDocks();
} else {
showZenDocks();
}
}
}
void MainWindow::loadLayouts(QSettings &settings)
{
this->layouts.clear();
int size = settings.beginReadArray("layouts");
for (int i = 0; i < size; i++) {
CutterLayout layout;
settings.setArrayIndex(i);
QString name = settings.value("name", "layout").toString();
layout.geometry = settings.value("geometry").toByteArray();
layout.state = settings.value("state").toByteArray();
auto docks = settings.value("docks").toMap();
for (auto it = docks.begin(), end = docks.end(); it != end; it++) {
layout.viewProperties.insert(it.key(), it.value().toMap());
}
layouts.insert(name, std::move(layout));
}
settings.endArray();
updateLayoutsMenu();
}
void MainWindow::saveLayouts(QSettings &settings)
{
settings.beginWriteArray("layouts", layouts.size());
int arrayIndex = 0;
for (auto it = layouts.begin(), end = layouts.end(); it != end; ++it, ++arrayIndex) {
settings.setArrayIndex(arrayIndex);
settings.setValue("name", it.key());
auto &layout = it.value();
settings.setValue("state", layout.state);
settings.setValue("geometry", layout.geometry);
QVariantMap properties;
for (auto it = layout.viewProperties.begin(), end = layout.viewProperties.end(); it != end; ++it) {
properties.insert(it.key(), it.value());
}
settings.setValue("docks", properties);
}
settings.endArray();
}
void MainWindow::on_actionLock_triggered()
@ -1323,22 +1399,12 @@ void MainWindow::on_actionFunctionsRename_triggered()
void MainWindow::on_actionDefault_triggered()
{
QSettings s;
restoreState(emptyState);
initCorners();
resetDockWidgetList();
if (core->currentlyDebugging) {
resetToDefaultLayout();
saveSettings();
resetToDebugLayout();
layouts[LAYOUT_DEBUG] = {};
setViewLayout(layouts[LAYOUT_DEBUG]);
} else {
resetToDebugLayout();
saveDebugSettings();
resetToDefaultLayout();
layouts[LAYOUT_DEFAULT] = {};
setViewLayout(layouts[LAYOUT_DEFAULT]);
}
}
@ -1419,7 +1485,8 @@ void MainWindow::on_actionReset_settings_triggered()
QMessageBox::Ok | QMessageBox::Cancel);
if (ret == QMessageBox::Ok) {
Config()->resetAll();
on_actionDefault_triggered();
readSettings();
setViewLayout(getViewLayout(Core()->currentlyDebugging ? LAYOUT_DEBUG : LAYOUT_DEFAULT));
}
}
@ -1586,19 +1653,17 @@ void MainWindow::projectSaved(bool successfully, const QString &name)
void MainWindow::toggleDebugView()
{
MemoryWidgetType memType = getMemoryWidgetTypeToRestore();
if (Core()->currentlyDebugging) {
saveSettings();
restoreDebugLayout();
layouts[LAYOUT_DEFAULT] = getViewLayout();
setViewLayout(getViewLayout(LAYOUT_DEBUG));
enableDebugWidgetsMenu(true);
} else {
saveDebugSettings();
MemoryWidgetType memType = getMemoryWidgetTypeToRestore();
hideAllDocks();
restoreDocks();
readSettingsOrDefault();
layouts[LAYOUT_DEBUG] = getViewLayout();
setViewLayout(getViewLayout(LAYOUT_DEFAULT));
enableDebugWidgetsMenu(false);
showMemoryWidget(memType);
}
showMemoryWidget(memType);
}
void MainWindow::mousePressEvent(QMouseEvent *event)

View File

@ -55,6 +55,13 @@ namespace Ui {
class MainWindow;
}
struct CutterLayout
{
QByteArray geometry;
QByteArray state;
QMap<QString, QVariantMap> viewProperties;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
@ -85,21 +92,20 @@ public:
void closeEvent(QCloseEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void readSettingsOrDefault();
void readSettings();
void saveSettings();
void readDebugSettings();
void saveDebugSettings();
void setFilename(const QString &fn);
void refreshOmniBar(const QStringList &flags);
void addWidget(QDockWidget *widget);
void addWidget(CutterDockWidget *widget);
void addMemoryDockWidget(MemoryDockWidget *widget);
void removeWidget(QDockWidget *widget);
void removeWidget(CutterDockWidget *widget);
void addExtraWidget(CutterDockWidget *extraDock);
MemoryDockWidget *addNewMemoryWidget(MemoryWidgetType type, RVA address, bool synchronized = true);
void addPluginDockWidget(QDockWidget *dockWidget, QAction *action);
CUTTER_DEPRECATED("Action will be ignored. Use addPluginDockWidget(CutterDockWidget*) instead.")
void addPluginDockWidget(CutterDockWidget *dockWidget, QAction *) { addPluginDockWidget(dockWidget); }
void addPluginDockWidget(CutterDockWidget *dockWidget);
enum class MenuType { File, Edit, View, Windows, Debug, Help, Plugins };
/**
* @brief Getter for MainWindow's different menus
@ -109,8 +115,6 @@ public:
QMenu *getMenuByType(MenuType type);
void addMenuFileAction(QAction *action);
void updateDockActionChecked(QAction * action);
QString getFilename() const
{
return filename;
@ -233,10 +237,11 @@ private:
Configuration *configuration;
QList<QDockWidget *> dockWidgets;
QMultiMap<QAction *, QDockWidget *> dockWidgetsOfAction;
QList<CutterDockWidget *> dockWidgets;
QList<CutterDockWidget *> pluginDocks;
DecompilerWidget *decompilerDock = nullptr;
OverviewWidget *overviewDock = nullptr;
QAction *actionOverview = nullptr;
EntrypointWidget *entrypointDock = nullptr;
FunctionsWidget *functionsDock = nullptr;
ImportsWidget *importsDock = nullptr;
@ -250,7 +255,6 @@ private:
StringsWidget *stringsDock = nullptr;
FlagsWidget *flagsDock = nullptr;
Dashboard *dashboardDock = nullptr;
QLineEdit *gotoEntry = nullptr;
SdbWidget *sdbDock = nullptr;
SectionsWidget *sectionsDock = nullptr;
SegmentsWidget *segmentsDock = nullptr;
@ -259,40 +263,44 @@ private:
ClassesWidget *classesDock = nullptr;
ResourcesWidget *resourcesDock = nullptr;
VTablesWidget *vTablesDock = nullptr;
DisassemblerGraphView *graphView = nullptr;
QDockWidget *asmDock = nullptr;
QDockWidget *calcDock = nullptr;
QDockWidget *stackDock = nullptr;
QDockWidget *threadsDock = nullptr;
QDockWidget *processesDock = nullptr;
QDockWidget *registersDock = nullptr;
QDockWidget *backtraceDock = nullptr;
QDockWidget *memoryMapDock = nullptr;
CutterDockWidget *stackDock = nullptr;
CutterDockWidget *threadsDock = nullptr;
CutterDockWidget *processesDock = nullptr;
CutterDockWidget *registersDock = nullptr;
CutterDockWidget *backtraceDock = nullptr;
CutterDockWidget *memoryMapDock = nullptr;
NewFileDialog *newFileDialog = nullptr;
QDockWidget *breakpointDock = nullptr;
QDockWidget *registerRefsDock = nullptr;
CutterDockWidget *breakpointDock = nullptr;
CutterDockWidget *registerRefsDock = nullptr;
QMenu *disassemblyContextMenuExtensions = nullptr;
QMenu *addressableContextMenuExtensions = nullptr;
QMap<QString, CutterLayout> layouts;
void initUI();
void initToolBar();
void initDocks();
void initLayout();
void initCorners();
void initBackForwardMenu();
void displayInitialOptionsDialog(const InitialOptions &options = InitialOptions(), bool skipOptionsDialog = false);
void resetToDefaultLayout();
void resetToDebugLayout();
void restoreDebugLayout();
CutterLayout getViewLayout();
CutterLayout getViewLayout(const QString &name);
void setViewLayout(const CutterLayout &layout);
void loadLayouts(QSettings &settings);
void saveLayouts(QSettings &settings);
void updateMemberPointers();
void resetDockWidgetList();
void restoreDocks();
void hideAllDocks();
void showZenDocks();
void showDebugDocks();
/**
* @brief Try to guess which is the "main" section of layout and dock there.
* @param widget that needs to be docked
*/
void dockOnMainArea(QDockWidget *widget);
void enableDebugWidgetsMenu(bool enable);
/**
* @brief Fill menu with seek history entries.
@ -300,10 +308,9 @@ private:
* @param redo set to false for undo history, true for redo.
*/
void updateHistoryMenu(QMenu *menu, bool redo = false);
void updateLayoutsMenu();
void saveNamedLayout();
void toggleDockWidget(QDockWidget *dock_widget, bool show);
void updateDockActionsChecked();
void setOverviewData();
bool isOverviewActive();
/**
@ -312,16 +319,18 @@ private:
* @return true for debug specific widgets, false for all other including common dock widgets.
*/
bool isDebugWidget(QDockWidget *dock) const;
bool isExtraMemoryWidget(QDockWidget *dock) const;
MemoryWidgetType getMemoryWidgetTypeToRestore();
/**
* @brief Map from a widget type (e.g. DisassemblyWidget::getWidgetType()) to the respective contructor of the widget
*/
QMap<QString, std::function<CutterDockWidget*(MainWindow*, QAction*)>> widgetTypeToConstructorMap;
QMap<QString, std::function<CutterDockWidget*(MainWindow*)>> widgetTypeToConstructorMap;
MemoryDockWidget* lastSyncMemoryWidget = nullptr;
MemoryDockWidget* lastMemoryWidget = nullptr;
int functionDockWidthToRestore = 0;
};
#endif // MAINWINDOW_H

View File

@ -102,6 +102,13 @@
<addaction name="actionGrouped_dock_dragging"/>
<addaction name="separator"/>
<addaction name="menuZoom"/>
<addaction name="actionSaveLayout"/>
<widget class="QMenu" name="menuLayouts">
<property name="title">
<string>Layouts</string>
</property>
</widget>
<addaction name="menuLayouts"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
@ -133,55 +140,20 @@
<property name="title">
<string>Info...</string>
</property>
<addaction name="actionClasses"/>
<addaction name="actionEntrypoints"/>
<addaction name="actionExports"/>
<addaction name="actionFlags"/>
<addaction name="actionHeaders"/>
<addaction name="actionImports"/>
<addaction name="actionRelocs"/>
<addaction name="actionResources"/>
<addaction name="actionSDBBrowser"/>
<addaction name="actionSections"/>
<addaction name="actionSegments"/>
<addaction name="actionSymbols"/>
<addaction name="actionVTables"/>
<addaction name="actionZignatures"/>
</widget>
<widget class="QMenu" name="menuAddDebugWidgets">
<property name="title">
<string>Debug...</string>
</property>
<addaction name="actionBacktrace"/>
<addaction name="actionBreakpoint"/>
<addaction name="actionThreads"/>
<addaction name="actionProcesses"/>
<addaction name="actionMemoryMap"/>
<addaction name="actionRegisters"/>
<addaction name="actionRegisterRefs"/>
<addaction name="actionStack"/>
</widget>
<addaction name="actionDashboard"/>
<addaction name="separator"/>
<addaction name="actionFunctions"/>
<addaction name="actionDecompiler"/>
<addaction name="actionOverview"/>
<addaction name="separator"/>
<addaction name="actionSearch"/>
<addaction name="actionStrings"/>
<addaction name="actionTypes"/>
<addaction name="separator"/>
<addaction name="actionExtraDisassembly"/>
<addaction name="actionExtraGraph"/>
<addaction name="actionExtraHexdump"/>
<addaction name="separator"/>
<addaction name="menuAddInfoWidgets"/>
<addaction name="menuAddDebugWidgets"/>
<addaction name="separator"/>
<addaction name="actionComments"/>
<addaction name="actionConsole"/>
<addaction name="separator"/>
<addaction name="menuPlugins"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menuDebug">
<property name="title">
@ -231,10 +203,7 @@
</widget>
<action name="actionDefault">
<property name="text">
<string>Reset Layout</string>
</property>
<property name="toolTip">
<string>Reset layout</string>
<string>Reset to default layout</string>
</property>
</action>
<action name="actionZen">
@ -399,105 +368,6 @@
<string>Lock/Unlock</string>
</property>
</action>
<action name="actionStrings">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Strings</string>
</property>
<property name="toolTip">
<string>Show/Hide Strings panel</string>
</property>
</action>
<action name="actionSections">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Sections</string>
</property>
<property name="toolTip">
<string>Show/Hide Sections panel</string>
</property>
</action>
<action name="actionSegments">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Segments</string>
</property>
<property name="toolTip">
<string>Show/Hide Segments panel</string>
</property>
</action>
<action name="actionFunctions">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Functions</string>
</property>
<property name="toolTip">
<string>Show/Hide Functions panel</string>
</property>
</action>
<action name="actionImports">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Imports</string>
</property>
<property name="toolTip">
<string>Show/Hide Imports panel</string>
</property>
</action>
<action name="actionSymbols">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Symbols</string>
</property>
<property name="toolTip">
<string>Show/Hide Symbols panel</string>
</property>
</action>
<action name="actionRelocs">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Relocs</string>
</property>
<property name="toolTip">
<string>Show/Hide Relocs panel</string>
</property>
</action>
<action name="actionFlags">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Flags</string>
</property>
<property name="toolTip">
<string>Show/Hide Flags panel</string>
</property>
</action>
<action name="actionMem">
<property name="checkable">
<bool>false</bool>
</property>
<property name="text">
<string>Memory</string>
</property>
<property name="toolTip">
<string>Show/Hide Memory panel</string>
</property>
</action>
<action name="actionTheme">
<property name="checkable">
<bool>false</bool>
@ -537,17 +407,6 @@
<string>Refresh</string>
</property>
</action>
<action name="actionComments">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Comments</string>
</property>
<property name="toolTip">
<string>Show/Hide comments</string>
</property>
</action>
<action name="actionTabs_on_Top">
<property name="checkable">
<bool>true</bool>
@ -776,30 +635,11 @@
<string>Show/Hide bottom pannel</string>
</property>
</action>
<action name="actionSDBBrowser">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>SDB Browser</string>
</property>
</action>
<action name="actionRun_Script">
<property name="text">
<string>Run Script</string>
</property>
</action>
<action name="actionDashboard">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Dashboard</string>
</property>
<property name="toolTip">
<string>Show/Hide Dashboard panel</string>
</property>
</action>
<action name="actionReset_settings">
<property name="text">
<string>Reset Settings</string>
@ -851,14 +691,6 @@
<string>Show pseudocode rather than assembly</string>
</property>
</action>
<action name="actionEntrypoints">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Entry Points</string>
</property>
</action>
<action name="actionDisplay_Offsets">
<property name="checkable">
<bool>true</bool>
@ -888,102 +720,6 @@
<string>Graph</string>
</property>
</action>
<action name="actionOverview">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Graph Overview</string>
</property>
</action>
<action name="actionDecompiler">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Decompiler</string>
</property>
</action>
<action name="actionConsole">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Console</string>
</property>
</action>
<action name="actionStack">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Stack</string>
</property>
</action>
<action name="actionRegisters">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Registers</string>
</property>
</action>
<action name="actionBacktrace">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Backtrace</string>
</property>
</action>
<action name="actionThreads">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Threads</string>
</property>
</action>
<action name="actionProcesses">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Processes</string>
</property>
</action>
<action name="actionMemoryMap">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Memory map</string>
</property>
</action>
<action name="actionBreakpoint">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Breakpoints</string>
</property>
</action>
<action name="actionRegisterRefs">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Register References</string>
</property>
</action>
<action name="actionClasses">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Classes</string>
</property>
</action>
<action name="actionImportPDB">
<property name="text">
<string>Import PDB</string>
@ -994,69 +730,6 @@
<string>Analyze</string>
</property>
</action>
<action name="actionResources">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Resources</string>
</property>
</action>
<action name="actionVTables">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>VTables</string>
</property>
<property name="toolTip">
<string>Show/Hide VTables panel</string>
</property>
</action>
<action name="actionTypes">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Types</string>
</property>
<property name="toolTip">
<string>Show/Hide Types panel</string>
</property>
</action>
<action name="actionSearch">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Search</string>
</property>
<property name="toolTip">
<string>Show/Hide Search panel</string>
</property>
</action>
<action name="actionHeaders">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Headers</string>
</property>
<property name="toolTip">
<string>Show/Hide Headers panel</string>
</property>
</action>
<action name="actionZignatures">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Zignatures</string>
</property>
<property name="toolTip">
<string>Show/Hide Zignatures panel</string>
</property>
</action>
<action name="actionExport_as_code">
<property name="text">
<string>Export as code</string>
@ -1126,6 +799,11 @@
<string>Commit changes</string>
</property>
</action>
<action name="actionSaveLayout">
<property name="text">
<string>Save layout</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -14,14 +14,12 @@ void CutterSamplePlugin::setupPlugin()
void CutterSamplePlugin::setupInterface(MainWindow *main)
{
QAction *action = new QAction("Sample C++ Plugin", main);
action->setCheckable(true);
CutterSamplePluginWidget *widget = new CutterSamplePluginWidget(main, action);
main->addPluginDockWidget(widget, action);
CutterSamplePluginWidget *widget = new CutterSamplePluginWidget(main);
main->addPluginDockWidget(widget);
}
CutterSamplePluginWidget::CutterSamplePluginWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action)
CutterSamplePluginWidget::CutterSamplePluginWidget(MainWindow *main) :
CutterDockWidget(main)
{
this->setObjectName("CutterSamplePluginWidget");
this->setWindowTitle("Sample C++ Plugin");

View File

@ -2,12 +2,12 @@
import cutter
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QAction, QVBoxLayout, QLabel, QWidget, QSizePolicy, QPushButton
from PySide2.QtWidgets import QVBoxLayout, QLabel, QWidget, QSizePolicy, QPushButton
class FortuneWidget(cutter.CutterDockWidget):
def __init__(self, parent, action):
super(FortuneWidget, self).__init__(parent, action)
def __init__(self, parent):
super(FortuneWidget, self).__init__(parent)
self.setObjectName("FancyDockWidgetFromCoolPlugin")
self.setWindowTitle("Sample Python Plugin")
@ -62,10 +62,8 @@ class CutterSamplePlugin(cutter.CutterPlugin):
def setupInterface(self, main):
# Dock widget
action = QAction("Sample Python Plugin", main)
action.setCheckable(True)
widget = FortuneWidget(main, action)
main.addPluginDockWidget(widget, action)
widget = FortuneWidget(main)
main.addPluginDockWidget(widget)
# Dissassembly context menu
menu = main.getContextMenuExtensions(cutter.MainWindow.ContextMenuType.Disassembly)

View File

@ -5,8 +5,8 @@
#include "core/MainWindow.h"
BacktraceWidget::BacktraceWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
BacktraceWidget::BacktraceWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::BacktraceWidget)
{
ui->setupUi(this);

View File

@ -19,7 +19,7 @@ class BacktraceWidget : public CutterDockWidget
Q_OBJECT
public:
explicit BacktraceWidget(MainWindow *main, QAction *action = nullptr);
explicit BacktraceWidget(MainWindow *main);
~BacktraceWidget();
private slots:
@ -32,4 +32,4 @@ private:
QStandardItemModel *modelBacktrace = new QStandardItemModel(1, 5, this);
QTableView *viewBacktrace = new QTableView(this);
RefreshDeferrer *refreshDeferrer;
};
};

View File

@ -173,8 +173,8 @@ BreakpointProxyModel::BreakpointProxyModel(BreakpointModel *sourceModel, QObject
this->setSortRole(Qt::EditRole);
}
BreakpointWidget::BreakpointWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
BreakpointWidget::BreakpointWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::BreakpointWidget)
{
ui->setupUi(this);

View File

@ -69,7 +69,7 @@ class BreakpointWidget : public CutterDockWidget
Q_OBJECT
public:
explicit BreakpointWidget(MainWindow *main, QAction *action = nullptr);
explicit BreakpointWidget(MainWindow *main);
~BreakpointWidget();
private slots:

View File

@ -575,8 +575,8 @@ bool ClassesSortFilterProxyModel::hasChildren(const QModelIndex &parent) const
ClassesWidget::ClassesWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
ClassesWidget::ClassesWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::ClassesWidget)
{
ui->setupUi(this);

View File

@ -175,7 +175,7 @@ class ClassesWidget : public CutterDockWidget
Q_OBJECT
public:
explicit ClassesWidget(MainWindow *main, QAction *action = nullptr);
explicit ClassesWidget(MainWindow *main);
~ClassesWidget();
private slots:

View File

@ -229,8 +229,8 @@ bool CommentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri
return false;
}
CommentsWidget::CommentsWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action),
CommentsWidget::CommentsWidget(MainWindow *main) :
ListDockWidget(main),
actionHorizontal(tr("Horizontal"), this),
actionVertical(tr("Vertical"), this)
{

View File

@ -75,7 +75,7 @@ class CommentsWidget : public ListDockWidget
Q_OBJECT
public:
explicit CommentsWidget(MainWindow *main, QAction *action = nullptr);
explicit CommentsWidget(MainWindow *main);
~CommentsWidget() override;
private slots:

View File

@ -37,8 +37,8 @@ static const int invalidHistoryPos = -1;
static const char *consoleWrapSettingsKey = "console.wrap";
ConsoleWidget::ConsoleWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
ConsoleWidget::ConsoleWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::ConsoleWidget),
debugOutputEnabled(true),
maxHistoryEntries(100),

View File

@ -24,7 +24,7 @@ class ConsoleWidget : public CutterDockWidget
Q_OBJECT
public:
explicit ConsoleWidget(MainWindow *main, QAction *action = nullptr);
explicit ConsoleWidget(MainWindow *main);
~ConsoleWidget();

View File

@ -1,26 +1,22 @@
#include "CutterDockWidget.h"
#include "core/MainWindow.h"
#include <QAction>
#include <QEvent>
#include <QtWidgets/QShortcut>
CutterDockWidget::CutterDockWidget(MainWindow *parent, QAction *action) :
QDockWidget(parent),
mainWindow(parent),
action(action)
CutterDockWidget::CutterDockWidget(MainWindow *parent, QAction *)
: CutterDockWidget(parent)
{
if (action) {
addAction(action);
connect(action, &QAction::triggered, this, &CutterDockWidget::toggleDockWidget);
}
if (parent) {
parent->addWidget(this);
}
}
CutterDockWidget::CutterDockWidget(MainWindow *parent) :
QDockWidget(parent),
mainWindow(parent)
{
// Install event filter to catch redraw widgets when needed
installEventFilter(this);
updateIsVisibleToUser();
connect(toggleViewAction(), &QAction::triggered, this, &QWidget::raise);
}
CutterDockWidget::~CutterDockWidget() = default;
@ -38,6 +34,15 @@ bool CutterDockWidget::eventFilter(QObject *object, QEvent *event)
return QDockWidget::eventFilter(object, event);
}
QVariantMap CutterDockWidget::serializeViewProprties()
{
return {};
}
void CutterDockWidget::deserializeViewProperties(const QVariantMap &)
{
}
void CutterDockWidget::toggleDockWidget(bool show)
{
if (!show) {
@ -68,25 +73,21 @@ void CutterDockWidget::updateIsVisibleToUser()
void CutterDockWidget::closeEvent(QCloseEvent *event)
{
if (action) {
this->action->setChecked(false);
}
QDockWidget::closeEvent(event);
if (isTransient) {
if (mainWindow) {
mainWindow->removeWidget(this);
}
// remove parent, otherwise dock layout may still decide to use this widget which is about to be deleted
setParent(nullptr);
deleteLater();
}
emit closed();
}
QAction *CutterDockWidget::getBoundAction() const
{
return action;
}
QString CutterDockWidget::getDockNumber()
{
auto name = this->objectName();

View File

@ -1,10 +1,11 @@
#ifndef CUTTERWIDGET_H
#define CUTTERWIDGET_H
#include <QDockWidget>
#include "CutterCommon.h"
#include "common/RefreshDeferrer.h"
#include <QDockWidget>
class MainWindow;
class CutterDockWidget : public QDockWidget
@ -12,7 +13,10 @@ class CutterDockWidget : public QDockWidget
Q_OBJECT
public:
explicit CutterDockWidget(MainWindow *parent, QAction *action = nullptr);
CUTTER_DEPRECATED("Action will be ignored. Use CutterDockWidget(MainWindow*) instead.")
CutterDockWidget(MainWindow *parent, QAction *action);
explicit CutterDockWidget(MainWindow *parent);
~CutterDockWidget() override;
bool eventFilter(QObject *object, QEvent *event) override;
bool isVisibleToUser() { return isVisibleToUserCurrent; }
@ -54,7 +58,34 @@ public:
});
return deferrer;
}
/**
* @brief Serialize dock properties for saving as part of layout.
*
* Override this function for saving dock specific view properties. Use
* in situations where it makes sense to have different properties for
* multiple instances of widget. Don't use for options that are more suitable
* as global settings and should be applied equally to all widgets or all
* widgets of this kind.
*
* Keep synchrononized with deserializeViewProperties. When modifying add
* project upgrade step in SettingsUpgrade.cpp if necessary.
*
* @return Dictionary of current dock properties.
* @see CutterDockWidget#deserializeViewProperties
*/
virtual QVariantMap serializeViewProprties();
/**
* @brief Deserialization half of serialize view properties.
*
* When a property is not specified in property map dock should reset it
* to default value instead of leaving it umodified. Empty map should reset
* all properties controlled by serializeViewProprties/deserializeViewProperties
* mechanism.
*
* @param properties to modify for current widget
* @see CutterDockWidget#serializeViewProprties
*/
virtual void deserializeViewProperties(const QVariantMap &properties);
signals:
void becameVisibleToUser();
void closed();
@ -66,14 +97,11 @@ protected:
virtual QWidget* widgetToFocusOnRaise();
void closeEvent(QCloseEvent *event) override;
QAction *getBoundAction() const;
QString getDockNumber();
MainWindow *mainWindow;
private:
QAction *action;
bool isTransient = false;
bool isVisibleToUserCurrent = false;

View File

@ -21,8 +21,8 @@
#include <QDialog>
#include <QTreeWidget>
Dashboard::Dashboard(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
Dashboard::Dashboard(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::Dashboard)
{
ui->setupUi(this);

View File

@ -21,7 +21,7 @@ class Dashboard : public CutterDockWidget
Q_OBJECT
public:
explicit Dashboard(MainWindow *main, QAction *action = nullptr);
explicit Dashboard(MainWindow *main);
~Dashboard();
private slots:

View File

@ -15,8 +15,8 @@
#include <QObject>
#include <QTextBlockUserData>
DecompilerWidget::DecompilerWidget(MainWindow *main, QAction *action) :
MemoryDockWidget(MemoryWidgetType::Decompiler, main, action),
DecompilerWidget::DecompilerWidget(MainWindow *main) :
MemoryDockWidget(MemoryWidgetType::Decompiler, main),
mCtxMenu(new DisassemblyContextMenu(this, main)),
ui(new Ui::DecompilerWidget)
{

View File

@ -25,7 +25,7 @@ protected:
DisassemblyContextMenu *mCtxMenu;
public:
explicit DecompilerWidget(MainWindow *main, QAction *action = nullptr);
explicit DecompilerWidget(MainWindow *main);
~DecompilerWidget();
public slots:
void showDisasContextMenu(const QPoint &pt);

View File

@ -38,8 +38,8 @@ static DisassemblyTextBlockUserData *getUserData(const QTextBlock &block)
return static_cast<DisassemblyTextBlockUserData *>(userData);
}
DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
: MemoryDockWidget(MemoryWidgetType::Disassembly, main, action)
DisassemblyWidget::DisassemblyWidget(MainWindow *main)
: MemoryDockWidget(MemoryWidgetType::Disassembly, main)
, mCtxMenu(new DisassemblyContextMenu(this, main))
, mDisasScrollArea(new DisassemblyScrollArea(this))
, mDisasTextEdit(new DisassemblyTextEdit(this))

View File

@ -22,7 +22,7 @@ class DisassemblyWidget : public MemoryDockWidget
{
Q_OBJECT
public:
explicit DisassemblyWidget(MainWindow *main, QAction *action = nullptr);
explicit DisassemblyWidget(MainWindow *main);
QWidget *getTextWidget();
static QString getWidgetType();

View File

@ -12,8 +12,8 @@
* Entrypoint Widget
*/
EntrypointWidget::EntrypointWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
EntrypointWidget::EntrypointWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::EntrypointWidget)
{
ui->setupUi(this);

View File

@ -19,7 +19,7 @@ class EntrypointWidget : public CutterDockWidget
Q_OBJECT
public:
explicit EntrypointWidget(MainWindow *main, QAction *action = nullptr);
explicit EntrypointWidget(MainWindow *main);
~EntrypointWidget();
private slots:

View File

@ -125,8 +125,8 @@ bool ExportsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
return leftExp.vaddr < rightExp.vaddr;
}
ExportsWidget::ExportsWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action)
ExportsWidget::ExportsWidget(MainWindow *main) :
ListDockWidget(main)
{
setWindowTitle(tr("Exports"));
setObjectName("ExportsWidget");
@ -138,8 +138,7 @@ ExportsWidget::ExportsWidget(MainWindow *main, QAction *action) :
QShortcut *toggle_shortcut = new QShortcut(widgetShortcuts["ExportsWidget"], main);
connect(toggle_shortcut, &QShortcut::activated, this, [=] (){
toggleDockWidget(true);
main->updateDockActionChecked(action);
toggleDockWidget(true);
} );
connect(Core(), &CutterCore::codeRebased, this, &ExportsWidget::refreshExports);

View File

@ -60,7 +60,7 @@ class ExportsWidget : public ListDockWidget
Q_OBJECT
public:
explicit ExportsWidget(MainWindow *main, QAction *action = nullptr);
explicit ExportsWidget(MainWindow *main);
~ExportsWidget();
private slots:

View File

@ -137,8 +137,8 @@ bool FlagsSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIn
}
FlagsWidget::FlagsWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
FlagsWidget::FlagsWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::FlagsWidget),
main(main),
tree(new CutterTreeWidget(this))

View File

@ -69,7 +69,7 @@ class FlagsWidget : public CutterDockWidget
Q_OBJECT
public:
explicit FlagsWidget(MainWindow *main, QAction *action = nullptr);
explicit FlagsWidget(MainWindow *main);
~FlagsWidget();
private slots:

View File

@ -424,8 +424,8 @@ bool FunctionSortFilterProxyModel::lessThan(const QModelIndex &left, const QMode
}
}
FunctionsWidget::FunctionsWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action),
FunctionsWidget::FunctionsWidget(MainWindow *main) :
ListDockWidget(main),
actionRename(tr("Rename"), this),
actionUndefine(tr("Undefine"), this),
actionHorizontal(tr("Horizontal"), this),

View File

@ -92,7 +92,7 @@ class FunctionsWidget : public ListDockWidget
Q_OBJECT
public:
explicit FunctionsWidget(MainWindow *main, QAction *action = nullptr);
explicit FunctionsWidget(MainWindow *main);
~FunctionsWidget() override;
void changeSizePolicy(QSizePolicy::Policy hor, QSizePolicy::Policy ver);

View File

@ -4,8 +4,8 @@
#include "WidgetShortcuts.h"
#include <QVBoxLayout>
GraphWidget::GraphWidget(MainWindow *main, QAction *action) :
MemoryDockWidget(MemoryWidgetType::Graph, main, action)
GraphWidget::GraphWidget(MainWindow *main) :
MemoryDockWidget(MemoryWidgetType::Graph, main)
{
setObjectName(main
? main->getUniqueObjectName(getWidgetType())

View File

@ -12,7 +12,7 @@ class GraphWidget : public MemoryDockWidget
Q_OBJECT
public:
explicit GraphWidget(MainWindow *main, QAction *action = nullptr);
explicit GraphWidget(MainWindow *main);
~GraphWidget() override {}
DisassemblerGraphView *getGraphView() const;

View File

@ -109,8 +109,8 @@ bool HeadersProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
return leftHeader.vaddr < rightHeader.vaddr;
}
HeadersWidget::HeadersWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action)
HeadersWidget::HeadersWidget(MainWindow *main) :
ListDockWidget(main)
{
setWindowTitle(tr("Headers"));
setObjectName("HeadersWidget");

View File

@ -68,7 +68,7 @@ class HeadersWidget : public ListDockWidget
Q_OBJECT
public:
explicit HeadersWidget(MainWindow *main, QAction *action = nullptr);
explicit HeadersWidget(MainWindow *main);
~HeadersWidget();
private slots:

View File

@ -147,7 +147,7 @@ public:
bool copy(void *out, uint64_t addr, size_t len) override {
if (addr < m_firstBlockAddr || addr > m_lastValidAddr ||
(m_lastValidAddr - addr + 1) < len /* do not merge with last check to handle overflows */) {
(m_lastValidAddr - addr + 1) < len /* do not merge with last check to handle overflows */ || m_blocks.isEmpty()) {
return false;
}

View File

@ -17,8 +17,8 @@
#include <QInputDialog>
#include <QShortcut>
HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) :
MemoryDockWidget(MemoryWidgetType::Hexdump, main, action),
HexdumpWidget::HexdumpWidget(MainWindow *main) :
MemoryDockWidget(MemoryWidgetType::Hexdump, main),
ui(new Ui::HexdumpWidget)
{
ui->setupUi(this);

View File

@ -31,7 +31,7 @@ class HexdumpWidget : public MemoryDockWidget
{
Q_OBJECT
public:
explicit HexdumpWidget(MainWindow *main, QAction *action = nullptr);
explicit HexdumpWidget(MainWindow *main);
~HexdumpWidget() override;
Highlighter *highlighter;

View File

@ -154,8 +154,8 @@ bool ImportsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
* Imports Widget
*/
ImportsWidget::ImportsWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action),
ImportsWidget::ImportsWidget(MainWindow *main) :
ListDockWidget(main),
importsModel(new ImportsModel(&imports, this)),
importsProxyModel(new ImportsProxyModel(importsModel, this))
{
@ -167,8 +167,7 @@ ImportsWidget::ImportsWidget(MainWindow *main, QAction *action) :
ui->treeView->sortByColumn(ImportsModel::LibraryColumn, Qt::AscendingOrder);
QShortcut *toggle_shortcut = new QShortcut(widgetShortcuts["ImportsWidget"], main);
connect(toggle_shortcut, &QShortcut::activated, this, [=] (){
toggleDockWidget(true);
main->updateDockActionChecked(action);
toggleDockWidget(true);
} );
connect(Core(), &CutterCore::codeRebased, this, &ImportsWidget::refreshImports);

View File

@ -77,7 +77,7 @@ class ImportsWidget : public ListDockWidget
Q_OBJECT
public:
explicit ImportsWidget(MainWindow *main, QAction *action);
explicit ImportsWidget(MainWindow *main);
~ImportsWidget();
private slots:

View File

@ -8,8 +8,8 @@
#include <QResizeEvent>
#include <QShortcut>
ListDockWidget::ListDockWidget(MainWindow *main, QAction *action, SearchBarPolicy searchBarPolicy) :
CutterDockWidget(main, action),
ListDockWidget::ListDockWidget(MainWindow *main, SearchBarPolicy searchBarPolicy) :
CutterDockWidget(main),
ui(new Ui::ListDockWidget),
tree(new CutterTreeWidget(this)),
searchBarPolicy(searchBarPolicy)

View File

@ -32,7 +32,7 @@ public:
Hide,
};
explicit ListDockWidget(MainWindow *main, QAction *action = nullptr, SearchBarPolicy searchBarPolicy = SearchBarPolicy::ShowByDefault);
explicit ListDockWidget(MainWindow *main, SearchBarPolicy searchBarPolicy = SearchBarPolicy::ShowByDefault);
~ListDockWidget() override;
void showCount(bool show);

View File

@ -6,8 +6,8 @@
#include <QMenu>
#include <QContextMenuEvent>
MemoryDockWidget::MemoryDockWidget(MemoryWidgetType type, MainWindow *parent, QAction *action)
: CutterDockWidget(parent, action)
MemoryDockWidget::MemoryDockWidget(MemoryWidgetType type, MainWindow *parent)
: CutterDockWidget(parent)
, mType(type)
, seekable(new CutterSeekable(this))
, syncAction(tr("Sync/unsync offset"), this)
@ -40,11 +40,6 @@ bool MemoryDockWidget::tryRaiseMemoryWidget()
void MemoryDockWidget::raiseMemoryWidget()
{
if (getBoundAction()) {
getBoundAction()->setChecked(true);
}
show();
raise();
widgetToFocusOnRaise()->setFocus(Qt::FocusReason::TabFocusReason);
@ -58,6 +53,19 @@ bool MemoryDockWidget::eventFilter(QObject *object, QEvent *event)
return CutterDockWidget::eventFilter(object, event);
}
QVariantMap MemoryDockWidget::serializeViewProprties()
{
auto result = CutterDockWidget::serializeViewProprties();
result["synchronized"] = seekable->isSynchronized();
return result;
}
void MemoryDockWidget::deserializeViewProperties(const QVariantMap &properties)
{
QVariant synchronized = properties.value("synchronized", true);
seekable->setSynchronization(synchronized.toBool());
}
void MemoryDockWidget::updateWindowTitle()
{
QString name = getWindowTitle();

View File

@ -15,7 +15,7 @@ class MemoryDockWidget : public CutterDockWidget
{
Q_OBJECT
public:
MemoryDockWidget(MemoryWidgetType type, MainWindow *parent, QAction *action = nullptr);
MemoryDockWidget(MemoryWidgetType type, MainWindow *parent);
~MemoryDockWidget() override {}
CutterSeekable *getSeekable() const;
@ -27,6 +27,9 @@ public:
return mType;
}
bool eventFilter(QObject *object, QEvent *event) override;
QVariantMap serializeViewProprties() override;
void deserializeViewProperties(const QVariantMap &properties) override;
private:
MemoryWidgetType mType;

View File

@ -111,8 +111,8 @@ bool MemoryProxyModel::lessThan(const QModelIndex &left, const QModelIndex &righ
return leftMemMap.addrStart < rightMemMap.addrStart;
}
MemoryMapWidget::MemoryMapWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action, ListDockWidget::SearchBarPolicy::HideByDefault)
MemoryMapWidget::MemoryMapWidget(MainWindow *main) :
ListDockWidget(main, ListDockWidget::SearchBarPolicy::HideByDefault)
{
setWindowTitle(tr("Memory Map"));
setObjectName("MemoryMapWidget");

View File

@ -67,7 +67,7 @@ class MemoryMapWidget : public ListDockWidget
Q_OBJECT
public:
explicit MemoryMapWidget(MainWindow *main, QAction *action = nullptr);
explicit MemoryMapWidget(MainWindow *main);
~MemoryMapWidget();
private slots:

View File

@ -3,8 +3,8 @@
#include "GraphWidget.h"
#include "OverviewView.h"
OverviewWidget::OverviewWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action)
OverviewWidget::OverviewWidget(MainWindow *main) :
CutterDockWidget(main)
{
setWindowTitle("Graph Overview");
setObjectName("Graph Overview");

View File

@ -12,7 +12,7 @@ class OverviewWidget : public CutterDockWidget
Q_OBJECT
public:
explicit OverviewWidget(MainWindow *main, QAction *action = nullptr);
explicit OverviewWidget(MainWindow *main);
~OverviewWidget();
private:

View File

@ -16,8 +16,8 @@ enum ColumnIndex {
COLUMN_PATH,
};
ProcessesWidget::ProcessesWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
ProcessesWidget::ProcessesWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::ProcessesWidget)
{
ui->setupUi(this);

View File

@ -31,7 +31,7 @@ class ProcessesWidget : public CutterDockWidget
Q_OBJECT
public:
explicit ProcessesWidget(MainWindow *main, QAction *action = nullptr);
explicit ProcessesWidget(MainWindow *main);
~ProcessesWidget();
private slots:

View File

@ -111,8 +111,8 @@ bool RegisterRefProxyModel::lessThan(const QModelIndex &left, const QModelIndex
return leftRegRef.reg < rightRegRef.reg;
}
RegisterRefsWidget::RegisterRefsWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
RegisterRefsWidget::RegisterRefsWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::RegisterRefsWidget),
tree(new CutterTreeWidget(this)),
addressableItemContextMenu(this, main)

View File

@ -69,7 +69,7 @@ class RegisterRefsWidget : public CutterDockWidget
Q_OBJECT
public:
explicit RegisterRefsWidget(MainWindow *main, QAction *action = nullptr);
explicit RegisterRefsWidget(MainWindow *main);
~RegisterRefsWidget();
private slots:

View File

@ -8,8 +8,8 @@
#include <QLabel>
#include <QLineEdit>
RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
RegistersWidget::RegistersWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::RegistersWidget),
addressContextMenu(this, main)
{

View File

@ -21,7 +21,7 @@ class RegistersWidget : public CutterDockWidget
Q_OBJECT
public:
explicit RegistersWidget(MainWindow *main, QAction *action = nullptr);
explicit RegistersWidget(MainWindow *main);
~RegistersWidget();
private slots:

View File

@ -113,8 +113,8 @@ bool RelocsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &righ
return false;
}
RelocsWidget::RelocsWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action),
RelocsWidget::RelocsWidget(MainWindow *main) :
ListDockWidget(main),
relocsModel(new RelocsModel(&relocs, this)),
relocsProxyModel(new RelocsProxyModel(relocsModel, this))
{

View File

@ -54,7 +54,7 @@ class RelocsWidget : public ListDockWidget
Q_OBJECT
public:
explicit RelocsWidget(MainWindow *main, QAction *action = nullptr);
explicit RelocsWidget(MainWindow *main);
~RelocsWidget();
private slots:

View File

@ -79,8 +79,8 @@ RVA ResourcesModel::address(const QModelIndex &index) const
return res.vaddr;
}
ResourcesWidget::ResourcesWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action, ListDockWidget::SearchBarPolicy::HideByDefault)
ResourcesWidget::ResourcesWidget(MainWindow *main) :
ListDockWidget(main, ListDockWidget::SearchBarPolicy::HideByDefault)
{
setObjectName("ResourcesWidget");

View File

@ -45,7 +45,7 @@ private:
QList<ResourcesDescription> resources;
public:
explicit ResourcesWidget(MainWindow *main, QAction *action = nullptr);
explicit ResourcesWidget(MainWindow *main);
private slots:
void refreshResources();

View File

@ -8,8 +8,8 @@
#include <QTreeWidget>
SdbWidget::SdbWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
SdbWidget::SdbWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::SdbWidget)
{
ui->setupUi(this);

View File

@ -17,7 +17,7 @@ class SdbWidget : public CutterDockWidget
Q_OBJECT
public:
explicit SdbWidget(MainWindow *main, QAction *action = nullptr);
explicit SdbWidget(MainWindow *main);
~SdbWidget();
private slots:

View File

@ -167,8 +167,8 @@ bool SearchSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelI
}
SearchWidget::SearchWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
SearchWidget::SearchWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::SearchWidget)
{
ui->setupUi(this);

View File

@ -64,7 +64,7 @@ class SearchWidget : public CutterDockWidget
Q_OBJECT
public:
explicit SearchWidget(MainWindow *main, QAction *action = nullptr);
explicit SearchWidget(MainWindow *main);
~SearchWidget();
private slots:

View File

@ -154,8 +154,8 @@ bool SectionsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri
}
}
SectionsWidget::SectionsWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action)
SectionsWidget::SectionsWidget(MainWindow *main) :
ListDockWidget(main)
{
setObjectName("SectionsWidget");
setWindowTitle(QStringLiteral("Sections"));

View File

@ -67,7 +67,7 @@ class SectionsWidget : public ListDockWidget
Q_OBJECT
public:
explicit SectionsWidget(MainWindow *main, QAction *action = nullptr);
explicit SectionsWidget(MainWindow *main);
~SectionsWidget();
private slots:

View File

@ -130,8 +130,8 @@ bool SegmentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri
return false;
}
SegmentsWidget::SegmentsWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action)
SegmentsWidget::SegmentsWidget(MainWindow *main) :
ListDockWidget(main)
{
setObjectName("SegmentsWidget");
setWindowTitle(QStringLiteral("Segments"));

View File

@ -53,7 +53,7 @@ class SegmentsWidget : public ListDockWidget
Q_OBJECT
public:
explicit SegmentsWidget(MainWindow *main, QAction *action = nullptr);
explicit SegmentsWidget(MainWindow *main);
~SegmentsWidget();
private slots:

View File

@ -8,8 +8,8 @@
#include "QHeaderView"
#include "QMenu"
StackWidget::StackWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
StackWidget::StackWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::StackWidget),
menuText(this),
addressableItemContextMenu(this, main)

View File

@ -52,7 +52,7 @@ class StackWidget : public CutterDockWidget
Q_OBJECT
public:
explicit StackWidget(MainWindow *main, QAction *action = nullptr);
explicit StackWidget(MainWindow *main);
~StackWidget();
private slots:

View File

@ -137,8 +137,8 @@ bool StringsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
return leftStr->vaddr < rightStr->vaddr;
}
StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
StringsWidget::StringsWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::StringsWidget),
tree(new CutterTreeWidget(this))
{
@ -154,8 +154,7 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
QShortcut *toggle_shortcut = new QShortcut(widgetShortcuts["StringsWidget"], main);
connect(toggle_shortcut, &QShortcut::activated, this, [ = ] () {
toggleDockWidget(true);
main->updateDockActionChecked(action);
} );
});
connect(ui->actionCopy_String, SIGNAL(triggered()), this, SLOT(on_actionCopy()));

View File

@ -70,7 +70,7 @@ class StringsWidget : public CutterDockWidget
Q_OBJECT
public:
explicit StringsWidget(MainWindow *main, QAction *action = nullptr);
explicit StringsWidget(MainWindow *main);
~StringsWidget();
private slots:

View File

@ -113,8 +113,8 @@ bool SymbolsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
return false;
}
SymbolsWidget::SymbolsWidget(MainWindow *main, QAction *action) :
ListDockWidget(main, action)
SymbolsWidget::SymbolsWidget(MainWindow *main) :
ListDockWidget(main)
{
setWindowTitle(tr("Symbols"));
setObjectName("SymbolsWidget");

View File

@ -58,7 +58,7 @@ class SymbolsWidget : public ListDockWidget
Q_OBJECT
public:
explicit SymbolsWidget(MainWindow *main, QAction *action = nullptr);
explicit SymbolsWidget(MainWindow *main);
~SymbolsWidget();
private slots:

View File

@ -15,8 +15,8 @@ enum ColumnIndex {
COLUMN_PATH,
};
ThreadsWidget::ThreadsWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
ThreadsWidget::ThreadsWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::ThreadsWidget)
{
ui->setupUi(this);

View File

@ -31,7 +31,7 @@ class ThreadsWidget : public CutterDockWidget
Q_OBJECT
public:
explicit ThreadsWidget(MainWindow *main, QAction *action = nullptr);
explicit ThreadsWidget(MainWindow *main);
~ThreadsWidget();
private slots:

View File

@ -127,8 +127,8 @@ bool TypesSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIn
TypesWidget::TypesWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
TypesWidget::TypesWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::TypesWidget),
tree(new CutterTreeWidget(this))
{

View File

@ -72,7 +72,7 @@ class TypesWidget : public CutterDockWidget
Q_OBJECT
public:
explicit TypesWidget(MainWindow *main, QAction *action = nullptr);
explicit TypesWidget(MainWindow *main);
~TypesWidget();
private slots:

View File

@ -127,8 +127,8 @@ bool VTableSortFilterProxyModel::filterAcceptsRow(int source_row,
}
VTablesWidget::VTablesWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
VTablesWidget::VTablesWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::VTablesWidget),
tree(new CutterTreeWidget(this))
{

View File

@ -56,7 +56,7 @@ class VTablesWidget : public CutterDockWidget
Q_OBJECT
public:
explicit VTablesWidget(MainWindow *main, QAction *action = nullptr);
explicit VTablesWidget(MainWindow *main);
~VTablesWidget();
private slots:

View File

@ -113,8 +113,8 @@ bool ZignaturesProxyModel::lessThan(const QModelIndex &left, const QModelIndex &
return leftZignature.offset < rightZignature.offset;
}
ZignaturesWidget::ZignaturesWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
ZignaturesWidget::ZignaturesWidget(MainWindow *main) :
CutterDockWidget(main),
ui(new Ui::ZignaturesWidget)
{
ui->setupUi(this);

View File

@ -61,7 +61,7 @@ class ZignaturesWidget : public CutterDockWidget
Q_OBJECT
public:
explicit ZignaturesWidget(MainWindow *main, QAction *action = nullptr);
explicit ZignaturesWidget(MainWindow *main);
~ZignaturesWidget();
private slots: