Add RefreshDeferrer

This commit is contained in:
Florian Märkl 2019-01-12 20:25:43 +01:00 committed by xarkes
parent 3728f977a2
commit b8c92a460d
7 changed files with 140 additions and 21 deletions

View File

@ -219,7 +219,8 @@ SOURCES += \
widgets/ComboQuickFilterView.cpp \
dialogs/HexdumpRangeDialog.cpp \
common/QtResImporter.cpp \
widgets/CutterSeekable.cpp
widgets/CutterSeekable.cpp \
common/RefreshDeferrer.cpp
HEADERS += \
Cutter.h \
@ -322,7 +323,8 @@ HEADERS += \
widgets/ComboQuickFilterView.h \
dialogs/HexdumpRangeDialog.h \
common/QtResImporter.h \
widgets/CutterSeekable.h
widgets/CutterSeekable.h \
common/RefreshDeferrer.h
FORMS += \
dialogs/AboutDialog.ui \

View File

@ -0,0 +1,37 @@
#include "RefreshDeferrer.h"
#include "widgets/CutterDockWidget.h"
RefreshDeferrer::RefreshDeferrer(RefreshDeferrerAccumulator *acc, QObject *parent) : QObject(parent),
acc(acc)
{
}
RefreshDeferrer::~RefreshDeferrer()
{
delete acc;
}
bool RefreshDeferrer::attemptRefresh(RefreshDeferrerParams params)
{
if (dockWidget->isVisibleToUser()) {
return true;
} else {
dirty = true;
acc->accumulate(params);
return false;
}
}
void RefreshDeferrer::registerFor(CutterDockWidget *dockWidget)
{
this->dockWidget = dockWidget;
connect(dockWidget, &CutterDockWidget::becameVisibleToUser, this, [this]() {
if(dirty) {
emit refreshNow(acc->result());
acc->clear();
dirty = false;
}
});
}

View File

@ -0,0 +1,83 @@
#ifndef REFRESHDEFERRER_H
#define REFRESHDEFERRER_H
#include <QObject>
class CutterDockWidget;
class RefreshDeferrer;
using RefreshDeferrerParams = void *;
using RefreshDeferrerParamsResult = void *;
class RefreshDeferrerAccumulator
{
friend class RefreshDeferrer;
public:
virtual ~RefreshDeferrerAccumulator() = default;
protected:
virtual void accumulate(RefreshDeferrerParams params) =0;
virtual void ignoreParams(RefreshDeferrerParams params) =0;
virtual void clear() =0;
virtual RefreshDeferrerParamsResult result() =0;
};
template<class T>
class ReplacingRefreshDeferrerAccumulator: public RefreshDeferrerAccumulator
{
private:
T *value = nullptr;
public:
~ReplacingRefreshDeferrerAccumulator() override
{
delete value;
}
protected:
void accumulate(RefreshDeferrerParams params) override
{
delete value;
value = static_cast<T *>(params);
}
void ignoreParams(RefreshDeferrerParams params) override
{
delete static_cast<T *>(params);
}
void clear() override
{
delete value;
value = nullptr;
}
virtual RefreshDeferrerParamsResult result() override
{
return value;
}
};
class RefreshDeferrer : public QObject
{
Q_OBJECT
private:
CutterDockWidget *dockWidget = nullptr;
RefreshDeferrerAccumulator *acc;
bool dirty = false;
public:
RefreshDeferrer(RefreshDeferrerAccumulator *acc, QObject *parent = nullptr);
virtual ~RefreshDeferrer();
bool attemptRefresh(RefreshDeferrerParams params);
void registerFor(CutterDockWidget *dockWidget);
signals:
void refreshNow(RefreshDeferrerParamsResult paramsResult);
};
#endif //REFRESHDEFERRER_H

View File

@ -12,10 +12,9 @@ CutterDockWidget::CutterDockWidget(MainWindow *main, QAction *action) :
connect(action, &QAction::triggered, this, &CutterDockWidget::toggleDockWidget);
}
isVisibleToUserCurrent = false;
// Install event filter to catch redraw widgets when needed
installEventFilter(this);
updateIsVisibleToUser();
}
CutterDockWidget::~CutterDockWidget() {}

View File

@ -13,6 +13,7 @@ public:
explicit CutterDockWidget(MainWindow *main, QAction *action = nullptr);
~CutterDockWidget() override;
bool eventFilter(QObject *object, QEvent *event) override;
bool isVisibleToUser() { return isVisibleToUserCurrent; }
public slots:
void toggleDockWidget(bool show);
@ -28,7 +29,6 @@ private:
protected:
void closeEvent(QCloseEvent *event) override;
bool isVisibleToUser() { return isVisibleToUserCurrent; }
};
#endif // CUTTERWIDGET_H

View File

@ -42,6 +42,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
, mDisasScrollArea(new DisassemblyScrollArea(this))
, mDisasTextEdit(new DisassemblyTextEdit(this))
, seekable(new CutterSeekable(this))
, disasmRefresh(new ReplacingRefreshDeferrerAccumulator<RVA>)
{
topOffset = bottomOffset = RVA_INVALID;
cursorLineOffset = 0;
@ -63,6 +64,13 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
setupFonts();
setupColors();
disasmRefresh.registerFor(this);
connect(&disasmRefresh, &RefreshDeferrer::refreshNow, this, [this](RefreshDeferrerParamsResult paramsResult) {
printf("got refresh now!\n");
RVA *offset = static_cast<RVA *>(paramsResult);
refreshDisasm(*offset);
});
maxLines = 0;
updateMaxLines();
@ -175,13 +183,6 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
ADD_SHORTCUT(QKeySequence(Qt::CTRL + Qt::Key_Plus), &DisassemblyWidget::zoomIn)
ADD_SHORTCUT(QKeySequence(Qt::CTRL + Qt::Key_Minus), &DisassemblyWidget::zoomOut)
#undef ADD_SHORTCUT
connect(this, &CutterDockWidget::becameVisibleToUser, this, [this]() {
printf("ooh! we became visible!\n");
if (disasmDirty) {
refreshDisasm(disasmDirtyOffset);
}
});
}
void DisassemblyWidget::toggleSync()
@ -202,15 +203,11 @@ QWidget *DisassemblyWidget::getTextWidget()
void DisassemblyWidget::refreshDisasm(RVA offset)
{
if (!isVisibleToUser()) {
printf("setting dirty\n");
disasmDirty = true;
disasmDirtyOffset = offset;
if(!disasmRefresh.attemptRefresh(new RVA(offset))) {
printf("we tried to refresh, but shouldn't yet.\n");
return;
} else {
printf("now refreshing\n");
disasmDirty = false;
}
printf("ok, actually refreshing now!\n");
if (offset != RVA_INVALID) {
topOffset = offset;

View File

@ -4,6 +4,8 @@
#include "Cutter.h"
#include "CutterDockWidget.h"
#include "CutterSeekable.h"
#include "common/RefreshDeferrer.h"
#include <QTextEdit>
#include <QPlainTextEdit>
#include <QShortcut>
@ -57,8 +59,7 @@ private:
int cursorLineOffset;
bool seekFromCursor;
bool disasmDirty = false;
RVA disasmDirtyOffset = RVA_INVALID;
RefreshDeferrer disasmRefresh;
RVA readCurrentDisassemblyOffset();
RVA readDisassemblyOffset(QTextCursor tc);