diff --git a/src/common/CutterSeekable.cpp b/src/common/CutterSeekable.cpp index 0be56ee3..bf53ffc5 100644 --- a/src/common/CutterSeekable.cpp +++ b/src/common/CutterSeekable.cpp @@ -50,6 +50,7 @@ void CutterSeekable::toggleSynchronization() { synchronized = !synchronized; onCoreSeekChanged(Core()->getOffset()); + emit syncChanged(); } bool CutterSeekable::isSynchronized() diff --git a/src/common/CutterSeekable.h b/src/common/CutterSeekable.h index 617cd262..58664d4d 100644 --- a/src/common/CutterSeekable.h +++ b/src/common/CutterSeekable.h @@ -82,5 +82,5 @@ private: signals: void seekableSeekChanged(RVA addr); - + void syncChanged(); }; diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 880fbef1..6140ce04 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -105,6 +105,9 @@ #include #include +template +T* getNewInstance(MainWindow *m, QAction *a) { return new T(m, a); } + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), core(Core()), @@ -123,9 +126,16 @@ void MainWindow::initUI() { ui->setupUi(this); + mapper.insert("GraphWidget", {getNewInstance, ui->actionGraph}); + mapper.insert("DisassemblyWidget", {getNewInstance, ui->actionDisassembly}); + mapper.insert("HexdumpWidget", {getNewInstance, ui->actionHexdump}); + initToolBar(); initDocks(); + QSettings s; + s.setValue("state.empty", saveState()); + /* * Some global shortcuts */ @@ -246,8 +256,6 @@ void MainWindow::initToolBar() void MainWindow::initDocks() { dockWidgets.reserve(20); - disassemblyDock = new DisassemblyWidget(this, ui->actionDisassembly); - hexdumpDock = new HexdumpWidget(this, ui->actionHexdump); pseudocodeDock = new PseudocodeWidget(this, ui->actionPseudocode); consoleDock = new ConsoleWidget(this, ui->actionConsole); @@ -266,7 +274,6 @@ void MainWindow::initDocks() }); ui->actionOverview->setChecked(overviewDock->getUserOpened()); - graphDock = new GraphWidget(this, ui->actionGraph); sectionsDock = new SectionsWidget(this, ui->actionSections); segmentsDock = new SegmentsWidget(this, ui->actionSegments); entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints); @@ -293,6 +300,35 @@ void MainWindow::initDocks() classesDock = new ClassesWidget(this, ui->actionClasses); resourcesDock = new ResourcesWidget(this, ui->actionResources); vTablesDock = new VTablesWidget(this, ui->actionVTables); + + QSettings s; + QStringList docks = s.value("docks").toStringList(); + + // 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 (mapper.contains(className)) { + auto widget = mapper[className].first(this, mapper[className].second); + widget->setObjectName(it); + addExtraWidget(widget); + } + } + } + + updateMemberPointers(); + + if (!disassemblyDock) { + on_actionExtraDisassembly_triggered(); + } else if (!graphDock) { + on_actionExtraGraph_triggered(); + } else if (!hexdumpDock) { + on_actionExtraHexdump_triggered(); + } + + updateMemberPointers(); } void MainWindow::initLayout() @@ -301,10 +337,8 @@ void MainWindow::initLayout() enableDebugWidgetsMenu(false); // Restore saved settings readSettingsOrDefault(); - // 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); + + initCorners(); } void MainWindow::toggleOverview(bool visibility, GraphWidget *targetGraph) @@ -325,26 +359,29 @@ void MainWindow::updateTasksIndicator() void MainWindow::on_actionExtraGraph_triggered() { - auto *extraDock = new GraphWidget(this, nullptr); + auto *extraDock = new GraphWidget(this, ui->actionGraph); + extraDock->setObjectName(getUniqueObjectName(extraDock->metaObject()->className())); addExtraWidget(extraDock); } void MainWindow::on_actionExtraHexdump_triggered() { - auto *extraDock = new HexdumpWidget(this, nullptr); + auto *extraDock = new HexdumpWidget(this, ui->actionHexdump); + extraDock->setObjectName(getUniqueObjectName(extraDock->metaObject()->className())); addExtraWidget(extraDock); } void MainWindow::on_actionExtraDisassembly_triggered() { - auto *extraDock = new DisassemblyWidget(this, nullptr); + auto *extraDock = new DisassemblyWidget(this, ui->actionDisassembly); + extraDock->setObjectName(getUniqueObjectName(extraDock->metaObject()->className())); addExtraWidget(extraDock); } void MainWindow::addExtraWidget(CutterDockWidget *extraDock) { extraDock->setTransient(true); - addDockWidget(Qt::TopDockWidgetArea, extraDock); + addDockWidget(Qt::TopDockWidgetArea, extraDock, Qt::Orientation::Horizontal); auto restoreExtraDock = qhelpers::forceWidth(extraDock->widget(), 600); qApp->processEvents(); restoreExtraDock.restoreWidth(extraDock->widget()); @@ -380,7 +417,8 @@ QMenu *MainWindow::getMenuByType(MenuType type) void MainWindow::addPluginDockWidget(QDockWidget *dockWidget, QAction *action) { addDockWidget(Qt::TopDockWidgetArea, dockWidget); - addDockWidgetAction(dockWidget, action); + dockWidget->addAction(action); + addWidget(dockWidget); ui->menuPlugins->addAction(action); addDockWidget(Qt::DockWidgetArea::TopDockWidgetArea, dockWidget); updateDockActionChecked(action); @@ -491,6 +529,13 @@ void MainWindow::finalizeOpen() showMaximized(); + QSettings s; + QStringList unsync = s.value("unsync").toStringList(); + for (auto it : dockWidgets) { + if (unsync.contains(it->objectName())) { + qobject_cast(it)->toggleSync(); + } + } // Set focus to disasm or graph widget @@ -603,7 +648,7 @@ void MainWindow::readSettingsOrDefault() * Check if saved settings exist * If not, then read the default layout */ - if (!geo.length() && !state.length()) { + if (!geo.length() || !state.length()) { resetToDefaultLayout(); return; } @@ -639,6 +684,22 @@ void MainWindow::readSettingsOrDefault() void MainWindow::saveSettings() { QSettings settings; + + QStringList docks; + const QStringList syncable = QStringList() + << hexdumpDock->metaObject()->className() + << disassemblyDock->metaObject()->className() + << graphDock->metaObject()->className(); + QStringList unsync; + for (const auto &it : dockWidgets) { + docks.append(it->objectName()); + if (syncable.contains(it->metaObject()->className()) && + !qobject_cast(it)->isSynced()) { + unsync.append(it->objectName()); + } + } + settings.setValue("docks", docks); + settings.setValue("unsync", unsync); settings.setValue("geometry", saveGeometry()); settings.setValue("size", size()); settings.setValue("pos", pos()); @@ -725,22 +786,7 @@ void MainWindow::restoreDocks() addDockWidget(Qt::TopDockWidgetArea, overviewDock); // Function | Dashboard - splitDockWidget(overviewDock, dashboardDock, Qt::Horizontal); - splitDockWidget(functionsDock, overviewDock, Qt::Vertical); - - // In the lower half the console is the first widget - addDockWidget(Qt::BottomDockWidgetArea, consoleDock); - - // Console | Sections - splitDockWidget(consoleDock, sectionsDock, Qt::Horizontal); - splitDockWidget(consoleDock, segmentsDock, Qt::Horizontal); - - // Tabs for center (must be applied after splitDockWidget()) - tabifyDockWidget(sectionsDock, commentsDock); - tabifyDockWidget(segmentsDock, commentsDock); - tabifyDockWidget(dashboardDock, disassemblyDock); - tabifyDockWidget(dashboardDock, graphDock); - tabifyDockWidget(dashboardDock, hexdumpDock); + splitDockWidget(functionsDock, dashboardDock, Qt::Horizontal); tabifyDockWidget(dashboardDock, pseudocodeDock); tabifyDockWidget(dashboardDock, entrypointDock); tabifyDockWidget(dashboardDock, flagsDock); @@ -757,17 +803,31 @@ void MainWindow::restoreDocks() tabifyDockWidget(dashboardDock, resourcesDock); tabifyDockWidget(dashboardDock, vTablesDock); tabifyDockWidget(dashboardDock, sdbDock); + tabifyDockWidget(dashboardDock, memoryMapDock); + tabifyDockWidget(dashboardDock, breakpointDock); + tabifyDockWidget(dashboardDock, registerRefsDock); + for (const auto &it : dockWidgets) { + if (QRegExp("\\w+ \\d+").exactMatch(it->objectName())) { + tabifyDockWidget(dashboardDock, it); + } + } + + splitDockWidget(functionsDock, overviewDock, Qt::Vertical); + + // In the lower half the console is the first widget + addDockWidget(Qt::BottomDockWidgetArea, consoleDock); + + // Console | Sections + splitDockWidget(consoleDock, sectionsDock, Qt::Horizontal); + splitDockWidget(consoleDock, segmentsDock, Qt::Horizontal); + + tabifyDockWidget(sectionsDock, commentsDock); // Add Stack, Registers and Backtrace vertically stacked addDockWidget(Qt::TopDockWidgetArea, stackDock); splitDockWidget(stackDock, registersDock, Qt::Vertical); tabifyDockWidget(stackDock, backtraceDock); - // MemoryMap/Breakpoint/RegRefs widget goes in the center tabs - tabifyDockWidget(dashboardDock, memoryMapDock); - tabifyDockWidget(dashboardDock, breakpointDock); - tabifyDockWidget(dashboardDock, registerRefsDock); - updateDockActionsChecked(); } @@ -781,14 +841,85 @@ void MainWindow::hideAllDocks() void MainWindow::updateDockActionsChecked() { - for (auto i = dockWidgetActions.constBegin(); i != dockWidgetActions.constEnd(); i++) { - i.key()->setChecked(!i.value()->isHidden()); + for (auto i = dockWidgetsOfAction.constBegin(); i != dockWidgetsOfAction.constEnd(); i++) { + updateDockActionChecked(i.key()); + } +} + +QString MainWindow::getUniqueObjectName(const QString& className) const +{ + QStringList docks; + docks.reserve(dockWidgets.size()); + QString name; + for (const auto &it : dockWidgets) { + name = it->objectName(); + if (name.contains(className)) { + docks.push_back(name); + } + } + + if (docks.isEmpty()) { + return className; + } + + int id = 0; + while (docks.contains(className + " " + QString::number(id))) { + id++; + } + + return className + " " + QString::number(id); +} + +void MainWindow::initCorners() +{ + // TODO: Allow the user to select this option visually in the GUI settings + // Adjust the DockWidget areas + setCorner(Qt::TopLeftCorner, Qt::TopDockWidgetArea); + setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); + + setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea); + setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); +} + +void MainWindow::updateMemberPointers() +{ + QString className; + for (auto it : dockWidgets) { + className = it->metaObject()->className(); + if (className == "GraphWidget") { + graphDock = qobject_cast(it); + } else if (className == "DisassemblyWidget") { + disassemblyDock = qobject_cast(it); + } else if (className == "HexdumpWidget") { + hexdumpDock = qobject_cast(it); + } + } +} + +void MainWindow::addWidget(QDockWidget* widget) +{ + dockWidgets.push_back(widget); + for (auto action : widget->actions()) { + dockWidgetsOfAction.insert(action, widget); + connect(qobject_cast(widget), &CutterDockWidget::closed, + this, [this]() { + QDockWidget *widget = qobject_cast(sender()); + dockWidgets.removeOne(widget); + for (auto action : widget->actions()) { + dockWidgetsOfAction.remove(action, widget); + } + updateMemberPointers(); + }); } } void MainWindow::updateDockActionChecked(QAction *action) { - action->setChecked(!dockWidgetActions[action]->isHidden()); + 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() @@ -796,17 +927,20 @@ void MainWindow::showZenDocks() const QList zenDocks = { functionsDock, dashboardDock, stringsDock, - graphDock, - disassemblyDock, - hexdumpDock, searchDock, - importsDock, + hexdumpDock, + disassemblyDock, + graphDock, + importsDock }; + int width = functionsDock->maximumWidth(); + functionsDock->setMaximumWidth(200); for (auto w : dockWidgets) { if (zenDocks.contains(w)) { w->show(); } } + functionsDock->setMaximumWidth(width); updateDockActionsChecked(); } @@ -814,21 +948,24 @@ void MainWindow::showDebugDocks() { const QList debugDocks = { functionsDock, stringsDock, - graphDock, - disassemblyDock, - hexdumpDock, searchDock, stackDock, registersDock, + hexdumpDock, + disassemblyDock, + graphDock, backtraceDock, memoryMapDock, breakpointDock }; + int width = functionsDock->maximumWidth(); + functionsDock->setMaximumWidth(200); for (auto w : dockWidgets) { if (debugDocks.contains(w)) { w->show(); } } + functionsDock->setMaximumWidth(width); updateDockActionsChecked(); } @@ -874,6 +1011,23 @@ void MainWindow::restoreDebugLayout() } } +void MainWindow::resetDockWidgetList() +{ + QStringList isLeft; + QList toClose; + for (auto it : dockWidgets) { + if (isLeft.contains(it->metaObject()->className())) { + toClose.append(it); + } else if (QRegExp("\\w+ \\d+").exactMatch(it->objectName())) { + isLeft.append(it->metaObject()->className()); + } + } + for (auto it : toClose) { + it->close(); + } + updateMemberPointers(); +} + void MainWindow::on_actionLock_triggered() { panelLock = !panelLock; @@ -905,9 +1059,21 @@ void MainWindow::on_actionFunctionsRename_triggered() void MainWindow::on_actionDefault_triggered() { + QSettings s; + restoreState(s.value("state.empty").toByteArray()); + + initCorners(); + resetDockWidgetList(); + if (core->currentlyDebugging) { + resetToDefaultLayout(); + saveSettings(); + resetToDebugLayout(); } else { + resetToDebugLayout(); + saveDebugSettings(); + resetToDefaultLayout(); } } @@ -1195,16 +1361,6 @@ bool MainWindow::eventFilter(QObject *, QEvent *event) return false; } -void MainWindow::addToDockWidgetList(QDockWidget *dockWidget) -{ - this->dockWidgets.push_back(dockWidget); -} - -void MainWindow::addDockWidgetAction(QDockWidget *dockWidget, QAction *action) -{ - this->dockWidgetActions[action] = dockWidget; -} - /** * @brief Show a warning message box. * diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index 5d50433d..ef6e91b2 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -94,8 +94,7 @@ public: void setFilename(const QString &fn); void refreshOmniBar(const QStringList &flags); - void addToDockWidgetList(QDockWidget *dockWidget); - void addDockWidgetAction(QDockWidget *dockWidget, QAction *action); + void addWidget(QDockWidget* widget); void addExtraWidget(CutterDockWidget *extraDock); void addPluginDockWidget(QDockWidget *dockWidget, QAction *action); @@ -207,7 +206,7 @@ private: Configuration *configuration; QList dockWidgets; - QMap dockWidgetActions; + QMultiMap dockWidgetsOfAction; DisassemblyWidget *disassemblyDock = nullptr; HexdumpWidget *hexdumpDock = nullptr; PseudocodeWidget *pseudocodeDock = nullptr; @@ -249,12 +248,15 @@ private: void initToolBar(); void initDocks(); void initLayout(); + void initCorners(); void displayInitialOptionsDialog(const InitialOptions &options = InitialOptions(), bool skipOptionsDialog = false); void resetToDefaultLayout(); void resetToDebugLayout(); void restoreDebugLayout(); + void updateMemberPointers(); + void resetDockWidgetList(); void restoreDocks(); void hideAllDocks(); void showZenDocks(); @@ -266,6 +268,14 @@ private: void updateDockActionsChecked(); void setOverviewData(); bool isOverviewActive(); + + /** + * @brief Map, where key is class name an value is pair of + * pointer to class constructor and action that passed to this constructor. + */ + QMap, QAction*>> mapper; + + QString getUniqueObjectName(const QString &className) const; }; #endif // MAINWINDOW_H diff --git a/src/widgets/CutterDockWidget.cpp b/src/widgets/CutterDockWidget.cpp index 8f4d5822..6b925be2 100644 --- a/src/widgets/CutterDockWidget.cpp +++ b/src/widgets/CutterDockWidget.cpp @@ -8,12 +8,12 @@ CutterDockWidget::CutterDockWidget(MainWindow *parent, QAction *action) : QDockWidget(parent), action(action) { + if (action) { + addAction(action); + connect(action, &QAction::triggered, this, &CutterDockWidget::toggleDockWidget); + } if (parent) { - parent->addToDockWidgetList(this); - if (action) { - parent->addDockWidgetAction(this, action); - connect(action, &QAction::triggered, this, &CutterDockWidget::toggleDockWidget); - } + parent->addWidget(this); } // Install event filter to catch redraw widgets when needed @@ -39,7 +39,7 @@ bool CutterDockWidget::eventFilter(QObject *object, QEvent *event) void CutterDockWidget::toggleDockWidget(bool show) { if (!show) { - this->close(); + this->hide(); } else { this->show(); this->raise(); @@ -73,6 +73,8 @@ void CutterDockWidget::closeEvent(QCloseEvent *event) if (isTransient) { deleteLater(); } + + emit closed(); } QAction *CutterDockWidget::getBoundAction() const diff --git a/src/widgets/CutterDockWidget.h b/src/widgets/CutterDockWidget.h index 8793a4c2..96a9bfdb 100644 --- a/src/widgets/CutterDockWidget.h +++ b/src/widgets/CutterDockWidget.h @@ -57,6 +57,7 @@ public: signals: void becameVisibleToUser(); + void closed(); public slots: void toggleDockWidget(bool show); diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index e1f5eac8..21de228c 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -28,12 +28,12 @@ #include -DisassemblerGraphView::DisassemblerGraphView(QWidget *parent) +DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable) : GraphView(parent), mFontMetrics(nullptr), blockMenu(new DisassemblyContextMenu(this)), contextMenu(new QMenu(this)), - seekable(new CutterSeekable(this)) + seekable(seekable) { highlight_token = nullptr; auto *layout = new QVBoxLayout(this); @@ -106,7 +106,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent) actionExportGraph.setText(tr("Export Graph")); connect(&actionExportGraph, SIGNAL(triggered(bool)), this, SLOT(on_actionExportGraph_triggered())); actionSyncOffset.setText(tr("Sync/unsync offset")); - connect(&actionSyncOffset, SIGNAL(triggered(bool)), this, SLOT(toggleSync())); + connect(&actionSyncOffset, &QAction::triggered, this, [this]() { this->seekable->toggleSynchronization(); }); // Context menu that applies to everything contextMenu->addAction(&actionExportGraph); @@ -156,16 +156,6 @@ DisassemblerGraphView::~DisassemblerGraphView() } } -void DisassemblerGraphView::toggleSync() -{ - seekable->toggleSynchronization(); - if (seekable->isSynchronized()) { - parentWidget()->setWindowTitle(windowTitle); - } else { - parentWidget()->setWindowTitle(windowTitle + CutterSeekable::tr(" (unsynced)")); - } -} - void DisassemblerGraphView::refreshView() { initFont(); diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index 4cc6343e..f1b02af0 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -84,7 +84,7 @@ class DisassemblerGraphView : public GraphView }; public: - DisassemblerGraphView(QWidget *parent); + DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable); ~DisassemblerGraphView() override; std::unordered_map disassembly_blocks; virtual void drawBlock(QPainter &p, GraphView::GraphBlock &block) override; @@ -112,8 +112,6 @@ public slots: void colorsUpdatedSlot(); void fontsUpdatedSlot(); void onSeekChanged(RVA addr); - void toggleSync(); - void zoom(QPointF mouseRelativePos, double velocity); void zoomReset(); diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 3c219a5c..c84d5c65 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -38,19 +38,8 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action) , mCtxMenu(new DisassemblyContextMenu(this)) , mDisasScrollArea(new DisassemblyScrollArea(this)) , mDisasTextEdit(new DisassemblyTextEdit(this)) - , seekable(new CutterSeekable(this)) { - /* - * Ugly hack just for the layout issue - * QSettings saves the state with the object names - * By doing this hack, - * you can at least avoid some mess by dismissing all the Extra Widgets - */ - QString name = "Disassembly"; - if (!action) { - name = "Extra Disassembly"; - } - setObjectName(name); + setObjectName("DisassemblyWidget"); topOffset = bottomOffset = RVA_INVALID; cursorLineOffset = 0; @@ -187,17 +176,6 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action) #undef ADD_ACTION } -void DisassemblyWidget::toggleSync() -{ - QString windowTitle = tr("Disassembly"); - seekable->toggleSynchronization(); - if (seekable->isSynchronized()) { - setWindowTitle(windowTitle); - } else { - setWindowTitle(windowTitle + CutterSeekable::tr(" (unsynced)")); - } -} - void DisassemblyWidget::setPreviewMode(bool previewMode) { mDisasTextEdit->setContextMenuPolicy(previewMode diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 1ab5787d..737d3067 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -29,7 +29,6 @@ public slots: void fontsUpdatedSlot(); void colorsUpdatedSlot(); void seekPrev(); - void toggleSync(); void setPreviewMode(bool previewMode); protected slots: @@ -82,7 +81,6 @@ private: QList getSameWordsSelections(); QAction syncIt; - CutterSeekable *seekable; }; class DisassemblyScrollArea : public QAbstractScrollArea diff --git a/src/widgets/GraphWidget.cpp b/src/widgets/GraphWidget.cpp index bb1c62b4..6a38a957 100644 --- a/src/widgets/GraphWidget.cpp +++ b/src/widgets/GraphWidget.cpp @@ -6,19 +6,9 @@ GraphWidget::GraphWidget(MainWindow *main, QAction *action) : MemoryDockWidget(CutterCore::MemoryWidgetType::Graph, main, action) { - /* - * Ugly hack just for the layout issue - * QSettings saves the state with the object names - * By doing this hack, - * you can at least avoid some mess by dismissing all the Extra Widgets - */ - QString name = "Graph"; - if (!action) { - name = "Extra Graph"; - } - setObjectName(name); + setObjectName("GraphWidget"); setAllowedAreas(Qt::AllDockWidgetAreas); - graphView = new DisassemblerGraphView(this); + graphView = new DisassemblerGraphView(this, seekable); setWidget(graphView); // getting the name of the class is implementation defined, and cannot be diff --git a/src/widgets/HexdumpWidget.cpp b/src/widgets/HexdumpWidget.cpp index 899c1ddb..ee43a8a0 100644 --- a/src/widgets/HexdumpWidget.cpp +++ b/src/widgets/HexdumpWidget.cpp @@ -17,22 +17,11 @@ HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) : MemoryDockWidget(CutterCore::MemoryWidgetType::Hexdump, main, action), - ui(new Ui::HexdumpWidget), - seekable(new CutterSeekable(this)) + ui(new Ui::HexdumpWidget) { ui->setupUi(this); - /* - * Ugly hack just for the layout issue - * QSettings saves the state with the object names - * By doing this hack, - * you can at least avoid some mess by dismissing all the Extra Widgets - */ - QString name = "Hexdump"; - if (!action) { - name = "Extra Hexdump"; - } - setObjectName(name); + setObjectName("HexdumpWidget"); ui->copyMD5->setIcon(QIcon(":/img/icons/copy.svg")); ui->copySHA1->setIcon(QIcon(":/img/icons/copy.svg")); @@ -162,19 +151,6 @@ void HexdumpWidget::on_parseBitsComboBox_currentTextChanged(const QString &/*arg refreshSelectionInfo(); } - -void HexdumpWidget::toggleSync() -{ - QString windowTitle = tr("Hexdump"); - seekable->toggleSynchronization(); - if (seekable->isSynchronized()) { - setWindowTitle(windowTitle); - } else { - setWindowTitle(windowTitle + CutterSeekable::tr(" (unsynced)")); - } -} - - void HexdumpWidget::setupFonts() { QFont font = Config()->getFont(); diff --git a/src/widgets/HexdumpWidget.h b/src/widgets/HexdumpWidget.h index 3386943e..9bb51ca8 100644 --- a/src/widgets/HexdumpWidget.h +++ b/src/widgets/HexdumpWidget.h @@ -32,12 +32,11 @@ class HexdumpWidget : public MemoryDockWidget public: explicit HexdumpWidget(MainWindow *main, QAction *action = nullptr); ~HexdumpWidget(); - Highlighter *highlighter; + Highlighter *highlighter; public slots: void initParsing(); - void toggleSync(); protected: virtual void resizeEvent(QResizeEvent *event) override; @@ -58,7 +57,6 @@ private: void clearParseWindow(); QAction syncAction; - CutterSeekable *seekable; private slots: void onSeekChanged(RVA addr); diff --git a/src/widgets/MemoryDockWidget.cpp b/src/widgets/MemoryDockWidget.cpp index 84495643..4d59f252 100644 --- a/src/widgets/MemoryDockWidget.cpp +++ b/src/widgets/MemoryDockWidget.cpp @@ -1,12 +1,32 @@ #include "MemoryDockWidget.h" +#include "common/CutterSeekable.h" #include MemoryDockWidget::MemoryDockWidget(CutterCore::MemoryWidgetType type, MainWindow *parent, QAction *action) : CutterDockWidget(parent, action) - , mType(type) + , mType(type), seekable(new CutterSeekable(this)) { connect(Core(), &CutterCore::raisePrioritizedMemoryWidget, this, &MemoryDockWidget::handleRaiseMemoryWidget); + connect(seekable, &CutterSeekable::syncChanged, this, [this]() { + if (seekable->isSynchronized()) { + setWindowTitle(windowTitle().remove(CutterSeekable::tr(" (unsynced)"))); + } else { + setWindowTitle(windowTitle() + CutterSeekable::tr(" (unsynced)")); + } + }); +} + +bool MemoryDockWidget::isSynced() const +{ + return seekable && seekable->isSynchronized(); +} + +void MemoryDockWidget::toggleSync() +{ + if (seekable) { + seekable->toggleSynchronization(); + } } void MemoryDockWidget::handleRaiseMemoryWidget(CutterCore::MemoryWidgetType raiseType) diff --git a/src/widgets/MemoryDockWidget.h b/src/widgets/MemoryDockWidget.h index 65cbee05..3da15d7b 100644 --- a/src/widgets/MemoryDockWidget.h +++ b/src/widgets/MemoryDockWidget.h @@ -4,6 +4,8 @@ #include "CutterDockWidget.h" #include "core/Cutter.h" +class CutterSeekable; + class MemoryDockWidget : public CutterDockWidget { Q_OBJECT @@ -11,10 +13,19 @@ public: MemoryDockWidget(CutterCore::MemoryWidgetType type, MainWindow *parent, QAction *action = nullptr); ~MemoryDockWidget() {} + bool isSynced() const; + +public slots: + void toggleSync(); + private: void handleRaiseMemoryWidget(CutterCore::MemoryWidgetType raiseType); CutterCore::MemoryWidgetType mType; + +protected: + CutterSeekable *seekable = nullptr; + }; #endif // MEMORYDOCKWIDGET_H