From 1955de9e3ef6f52310bebb4a689c988332624bb0 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Sat, 17 Jan 2026 20:11:13 +0300 Subject: [PATCH] Detect when local changes occured to file --- src/Toolbar.cpp | 2 +- src/World.cpp | 1 + src/World.hpp | 1 + src/WorldUndoManager.cpp | 41 +++++++++++++++++++++++++++++++++++++--- src/WorldUndoManager.hpp | 6 ++++++ 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp index 7ab53b9..7c3d7a5 100644 --- a/src/Toolbar.cpp +++ b/src/Toolbar.cpp @@ -485,7 +485,7 @@ void Toolbar::top_toolbar() { } std::vector> tabNames; for(size_t i = 0; i < main.worlds.size(); i++) - tabNames.emplace_back(main.worlds[i]->netObjMan.is_connected() ? "data/icons/network.svg" : "", main.worlds[i]->name); + tabNames.emplace_back(main.worlds[i]->netObjMan.is_connected() ? "data/icons/network.svg" : "", main.worlds[i]->name + (main.worlds[i]->hasUnsavedLocalChanges ? "*" : "")); std::optional closedTab; gui.tab_list("file tab list", tabNames, main.worldIndex, closedTab); if(!main.world->clientStillConnecting) { diff --git a/src/World.cpp b/src/World.cpp index 3491694..0ba4851 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -404,6 +404,7 @@ void World::save_to_file(const std::filesystem::path& filePathToSaveAt) { #endif Logger::get().log("USERINFO", "File saved"); + undo.set_save_action(); } catch(const std::exception& e) { Logger::get().log("WORLDFATAL", std::string("Save error: ") + e.what()); diff --git a/src/World.hpp b/src/World.hpp index 0cd27e4..2b8d954 100644 --- a/src/World.hpp +++ b/src/World.hpp @@ -89,6 +89,7 @@ class World { void scale_up(const WorldScalar& scaleUpAmount); void scale_up_step(); + bool hasUnsavedLocalChanges = false; bool setToDestroy = false; NetworkingObjects::DelayUpdateSerializedClassManager delayedUpdateObjectManager; diff --git a/src/WorldUndoManager.cpp b/src/WorldUndoManager.cpp index 38ea625..8e403bc 100644 --- a/src/WorldUndoManager.cpp +++ b/src/WorldUndoManager.cpp @@ -1,4 +1,5 @@ #include "WorldUndoManager.hpp" +#include "World.hpp" void WorldUndoAction::scale_up(const WorldScalar& scaleAmount) {} WorldUndoAction::~WorldUndoAction() {} @@ -18,17 +19,23 @@ bool WorldUndoManager::can_redo() { void WorldUndoManager::push(std::unique_ptr undoAction) { push_undo(std::move(undoAction)); redoQueue.clear(); + world.hasUnsavedLocalChanges = true; } void WorldUndoManager::push_undo(std::unique_ptr undoAction) { - if(undoQueue.size() == UNDO_QUEUE_LIMIT) + if(undoQueue.size() == UNDO_QUEUE_LIMIT) { + if(undoActionSavedAt.has_value()) { + if(undoQueue.front().get() == undoActionSavedAt.value()) + undoActionSavedAt = nullptr; + else if(undoActionSavedAt.value() == nullptr) + undoActionSavedAt = std::nullopt; + } undoQueue.pop_front(); + } undoQueue.emplace_back(std::move(undoAction)); } void WorldUndoManager::push_redo(std::unique_ptr undoAction) { - if(redoQueue.size() == UNDO_QUEUE_LIMIT) - redoQueue.pop_front(); redoQueue.emplace_back(std::move(undoAction)); } @@ -41,6 +48,8 @@ void WorldUndoManager::undo() { push_redo(std::move(undoQueue.back())); undoQueue.pop_back(); } + + set_world_has_unsaved_local_changes(); } void WorldUndoManager::redo() { @@ -52,11 +61,14 @@ void WorldUndoManager::redo() { push_undo(std::move(redoQueue.back())); redoQueue.pop_back(); } + + set_world_has_unsaved_local_changes(); } void WorldUndoManager::clear() { redoQueue.clear(); undoQueue.clear(); + undoActionSavedAt = std::nullopt; } void WorldUndoManager::scale_up(const WorldScalar& scaleAmount) { @@ -142,3 +154,26 @@ std::vector WorldUndoManager::get_front_undo_queue_names(unsigned c } return toRet; } + +void WorldUndoManager::set_save_action() { + if(undoQueue.empty()) + undoActionSavedAt = nullptr; + else + undoActionSavedAt = undoQueue.back().get(); + world.hasUnsavedLocalChanges = false; +} + +void WorldUndoManager::set_world_has_unsaved_local_changes() { + // Saved action value meanings: + // - a pointer to an action: The file was saved when that undo action was the last one in place + // - nullptr: The file was saved when undoQueue was empty + // - nullopt: The undo action the file was saved at was lost + if(!undoActionSavedAt.has_value()) + world.hasUnsavedLocalChanges = true; + else { + if(undoQueue.empty()) + world.hasUnsavedLocalChanges = undoActionSavedAt.value() != nullptr; + else + world.hasUnsavedLocalChanges = undoActionSavedAt.value() != undoQueue.back().get(); + } +} diff --git a/src/WorldUndoManager.hpp b/src/WorldUndoManager.hpp index 267682f..b219d72 100644 --- a/src/WorldUndoManager.hpp +++ b/src/WorldUndoManager.hpp @@ -38,6 +38,8 @@ class WorldUndoManager { bool fill_netid_list_from_undoid_list(std::vector& netIDList, const std::vector& undoIDList); std::vector get_front_undo_queue_names(unsigned count); + void set_save_action(); + World& world; private: void push_undo(std::unique_ptr undoAction); @@ -49,5 +51,9 @@ class WorldUndoManager { std::deque> undoQueue; std::deque> redoQueue; + std::optional undoActionSavedAt = nullptr; + + void set_world_has_unsaved_local_changes(); + UndoObjectID lastUndoObjectID = 0; };