Skip to content

Commit

Permalink
Detect external changes to backing file (#124).
Browse files Browse the repository at this point in the history
  • Loading branch information
solemnwarning committed May 14, 2023
1 parent e27c7b5 commit aca5c04
Show file tree
Hide file tree
Showing 10 changed files with 715 additions and 142 deletions.
177 changes: 167 additions & 10 deletions src/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <stack>
#include <tuple>
#include <vector>
#include <wx/artprov.h>
#include <wx/clipbrd.h>
#include <wx/dataobj.h>
#include <wx/sizer.h>
Expand Down Expand Up @@ -77,7 +78,10 @@ REHex::Tab::Tab(wxWindow *parent):
htools_adjust_force(false),
htools_initial_size(-1),
repopulate_regions_frozen(false),
repopulate_regions_pending(false)
repopulate_regions_pending(false),
child_windows_hidden(false),
file_deleted_dialog_pending(false),
file_modified_dialog_pending(false)
{
v_splitter = new wxSplitterWindow(this, ID_VSPLITTER, wxDefaultPosition, wxDefaultSize, (wxSP_3D | wxSP_LIVE_UPDATE));
v_splitter->SetSashGravity(1.0);
Expand All @@ -100,12 +104,16 @@ REHex::Tab::Tab(wxWindow *parent):
doc.auto_cleanup_bind(EV_TYPES_CHANGED, &REHex::Tab::OnDocumentDataTypesChanged, this);
doc.auto_cleanup_bind(EV_MAPPINGS_CHANGED, &REHex::Tab::OnDocumentMappingsChanged, this);

doc.auto_cleanup_bind(BACKING_FILE_DELETED, &REHex::Tab::OnDocumentFileDeleted, this);
doc.auto_cleanup_bind(BACKING_FILE_MODIFIED, &REHex::Tab::OnDocumentFileModified, this);

doc_ctrl->Bind(wxEVT_CHAR, &REHex::Tab::OnDocumentCtrlChar, this);

doc.auto_cleanup_bind(CURSOR_UPDATE, &REHex::Tab::OnEventToForward<CursorUpdateEvent>, this);
doc.auto_cleanup_bind(EV_UNDO_UPDATE, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(EV_BECAME_DIRTY, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(EV_BECAME_CLEAN, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(CURSOR_UPDATE, &REHex::Tab::OnEventToForward<CursorUpdateEvent>, this);
doc.auto_cleanup_bind(EV_UNDO_UPDATE, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(EV_BECAME_DIRTY, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(EV_BECAME_CLEAN, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(DOCUMENT_TITLE_CHANGED, &REHex::Tab::OnEventToForward<DocumentTitleEvent>, this);

repopulate_regions();

Expand Down Expand Up @@ -151,7 +159,10 @@ REHex::Tab::Tab(wxWindow *parent, SharedDocumentPointer &document):
htools_adjust_force(false),
htools_initial_size(-1),
repopulate_regions_frozen(false),
repopulate_regions_pending(false)
repopulate_regions_pending(false),
child_windows_hidden(false),
file_deleted_dialog_pending(false),
file_modified_dialog_pending(false)
{
v_splitter = new wxSplitterWindow(this, ID_VSPLITTER, wxDefaultPosition, wxDefaultSize, (wxSP_3D | wxSP_LIVE_UPDATE));
v_splitter->SetSashGravity(1.0);
Expand All @@ -174,12 +185,16 @@ REHex::Tab::Tab(wxWindow *parent, SharedDocumentPointer &document):
doc.auto_cleanup_bind(EV_TYPES_CHANGED, &REHex::Tab::OnDocumentDataTypesChanged, this);
doc.auto_cleanup_bind(EV_MAPPINGS_CHANGED, &REHex::Tab::OnDocumentMappingsChanged, this);

doc.auto_cleanup_bind(BACKING_FILE_DELETED, &REHex::Tab::OnDocumentFileDeleted, this);
doc.auto_cleanup_bind(BACKING_FILE_MODIFIED, &REHex::Tab::OnDocumentFileModified, this);

doc_ctrl->Bind(wxEVT_CHAR, &REHex::Tab::OnDocumentCtrlChar, this);

doc.auto_cleanup_bind(CURSOR_UPDATE, &REHex::Tab::OnEventToForward<CursorUpdateEvent>, this);
doc.auto_cleanup_bind(EV_UNDO_UPDATE, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(EV_BECAME_DIRTY, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(EV_BECAME_CLEAN, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(CURSOR_UPDATE, &REHex::Tab::OnEventToForward<CursorUpdateEvent>, this);
doc.auto_cleanup_bind(EV_UNDO_UPDATE, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(EV_BECAME_DIRTY, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(EV_BECAME_CLEAN, &REHex::Tab::OnEventToForward<wxCommandEvent>, this);
doc.auto_cleanup_bind(DOCUMENT_TITLE_CHANGED, &REHex::Tab::OnEventToForward<DocumentTitleEvent>, this);

repopulate_regions();

Expand Down Expand Up @@ -321,6 +336,8 @@ void REHex::Tab::search_dialog_register(wxDialog *search_dialog)

void REHex::Tab::hide_child_windows()
{
child_windows_hidden = true;

for(auto sdi = search_dialogs.begin(); sdi != search_dialogs.end(); ++sdi)
{
(*sdi)->Hide();
Expand All @@ -329,10 +346,22 @@ void REHex::Tab::hide_child_windows()

void REHex::Tab::unhide_child_windows()
{
child_windows_hidden = false;

for(auto sdi = search_dialogs.begin(); sdi != search_dialogs.end(); ++sdi)
{
(*sdi)->ShowWithoutActivating();
}

if(file_deleted_dialog_pending)
{
file_modified_dialog_pending = false;
file_deleted_dialog();
}
else if(file_modified_dialog_pending)
{
file_modified_dialog();
}
}

void REHex::Tab::save_view(wxConfig *config)
Expand Down Expand Up @@ -1278,6 +1307,134 @@ void REHex::Tab::OnDocumentMappingsChanged(wxCommandEvent &event)
event.Skip();
}

void REHex::Tab::OnDocumentFileDeleted(wxCommandEvent &event)
{
OnEventToForward(event);
file_deleted_dialog();
}

void REHex::Tab::file_deleted_dialog()
{
if(child_windows_hidden)
{
file_deleted_dialog_pending = true;
return;
}

file_deleted_dialog_pending = false;

wxMessageDialog confirm(
this,
(wxString("The file ") + doc->get_filename() + " has been deleted from disk."),
"File deleted",
(wxYES_NO | wxCANCEL | wxCENTER));

confirm.SetYesNoCancelLabels("Save", "Save As", "Ignore");

int response = confirm.ShowModal();
switch(response)
{
case wxID_YES:
{
try {
doc->save();
}
catch(const std::exception &e)
{
wxMessageBox(
std::string("Error saving ") + doc->get_title() + ":\n" + e.what(),
"Error", wxICON_ERROR, this);
}

break;
}

case wxID_NO:
{
std::string new_filename = document_save_as_dialog(this, doc);
if(new_filename == "")
{
/* Cancelled. */
return;
}

try {
doc->save(new_filename);
}
catch(const std::exception &e)
{
wxMessageBox(
std::string("Error saving ") + doc->get_title() + ":\n" + e.what(),
"Error", wxICON_ERROR, this);
}

break;
}

default:
{
/* Ignore */
break;
}
}
}

void REHex::Tab::OnDocumentFileModified(wxCommandEvent &event)
{
OnEventToForward(event);
file_modified_dialog();
}

void REHex::Tab::file_modified_dialog()
{
if(child_windows_hidden)
{
file_modified_dialog_pending = true;
}

file_modified_dialog_pending = false;

if(doc->is_dirty())
{
wxMessageDialog confirm(
this,
(wxString("The file ") + doc->get_filename() + " has been modified externally AND in the editor.\n"
+ "DISCARD YOUR CHANGES and reload the file?"),
"File modified",
(wxYES_NO | wxICON_EXCLAMATION | wxCENTER));

int response = confirm.ShowModal();
if(response == wxNO)
{
return;
}
}
else{
wxMessageDialog confirm(
this,
(wxString("The file ") + doc->get_filename() + " has been modified externally.\n"
+ "Do you want to reload the file?"),
"File modified",
(wxYES_NO | wxICON_EXCLAMATION | wxCENTER));

int response = confirm.ShowModal();
if(response == wxNO)
{
return;
}
}

try {
doc->reload();
}
catch(const std::exception &e)
{
wxMessageBox(
std::string("Error reloading ") + doc->get_title() + ":\n" + e.what(),
"Error", wxICON_ERROR, this);
}
}

void REHex::Tab::OnBulkUpdatesFrozen(wxCommandEvent &event)
{
repopulate_regions_freeze();
Expand Down
13 changes: 12 additions & 1 deletion src/Tab.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* Reverse Engineer's Hex Editor
* Copyright (C) 2017-2022 Daniel Collins <[email protected]>
* Copyright (C) 2017-2023 Daniel Collins <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
Expand Down Expand Up @@ -127,6 +127,9 @@ namespace REHex
void OnDocumentDataTypesChanged(wxCommandEvent &event);
void OnDocumentMappingsChanged(wxCommandEvent &event);

void OnDocumentFileDeleted(wxCommandEvent &event);
void OnDocumentFileModified(wxCommandEvent &event);

void OnBulkUpdatesFrozen(wxCommandEvent &event);
void OnBulkUpdatesThawed(wxCommandEvent &event);

Expand Down Expand Up @@ -169,6 +172,14 @@ namespace REHex

void compare_range(off_t offset, off_t length);

bool child_windows_hidden;

bool file_deleted_dialog_pending;
void file_deleted_dialog();

bool file_modified_dialog_pending;
void file_modified_dialog();

DECLARE_EVENT_TABLE()
};
}
Expand Down
Loading

0 comments on commit aca5c04

Please sign in to comment.