Skip to content

Commit

Permalink
#5231: Add a message type to signal the start and finish of a long-ru…
Browse files Browse the repository at this point in the history
…nning operation. The UI can and will react to this by showing a blocking window on top of the mainframe.
  • Loading branch information
codereader committed May 9, 2020
1 parent 3123992 commit 4698288
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 8 deletions.
File renamed without changes.
52 changes: 52 additions & 0 deletions libs/messages/LongRunningOperationMessage.h
@@ -0,0 +1,52 @@
#pragma once

#include "imessagebus.h"

namespace radiant
{

enum class OperationEvent
{
Started,
Finished,
};

/**
* Message object sent to the MessageBus when one of the
* modules are performing a long-running operation.
*
* UI modules can react to this by showing a blocking
* window, depending on the event type as returned by getType().
*
* See also ScopedLongRunningOperation.h
*/
class LongRunningOperationMessage :
public radiant::IMessage
{
private:
OperationEvent _event;

std::string _title;

public:
LongRunningOperationMessage(OperationEvent ev) :
LongRunningOperationMessage(ev, std::string())
{}

LongRunningOperationMessage(OperationEvent ev, const std::string& title) :
_event(ev),
_title(title)
{}

OperationEvent getType() const
{
return _event;
}

const std::string& getTitle() const
{
return _title;
}
};

}
32 changes: 32 additions & 0 deletions libs/messages/ScopedLongRunningOperation.h
@@ -0,0 +1,32 @@
#pragma once

#include "iradiant.h"
#include "LongRunningOperationMessage.h"
#include "util/Noncopyable.h"

namespace radiant
{

/**
* Scoped helper class dispatching a LongRunningOperationMessage
* to DarkRadiant's message bus. The constructor will send
* the Started event, the destructor will do the Finished part
*/
class ScopedLongRunningOperation :
public util::Noncopyable
{
public:
ScopedLongRunningOperation(const std::string& title)
{
LongRunningOperationMessage started(OperationEvent::Started, title);
GlobalRadiantCore().getMessageBus().sendMessage(started);
}

~ScopedLongRunningOperation()
{
LongRunningOperationMessage finished(OperationEvent::Finished);
GlobalRadiantCore().getMessageBus().sendMessage(finished);
}
};

}
2 changes: 1 addition & 1 deletion radiant/RadiantApp.cpp
Expand Up @@ -6,7 +6,7 @@

#include "log/PIDFile.h"
#include "module/CoreModule.h"
#include "GameConfigNeededMessage.h"
#include "messages/GameConfigNeededMessage.h"
#include "ui/prefdialog/GameSetupDialog.h"
#include "module/StaticModule.h"

Expand Down
4 changes: 2 additions & 2 deletions radiant/eclassmgr/EClassManager.cpp
Expand Up @@ -10,6 +10,7 @@
#include "iradiant.h"
#include "ifilesystem.h"
#include "parser/DefTokeniser.h"
#include "messages/ScopedLongRunningOperation.h"

#include "Doom3EntityClass.h"
#include "Doom3ModelDef.h"
Expand Down Expand Up @@ -322,8 +323,7 @@ void EClassManager::shutdownModule()
// This takes care of relading the entityDefs and refreshing the scenegraph
void EClassManager::reloadDefsCmd(const cmd::ArgumentList& args)
{
IScopedScreenUpdateBlockerPtr blocker = GlobalMainFrame().getScopedScreenUpdateBlocker(_("Reloading Defs"),
_("Reloading Defs"), true);
radiant::ScopedLongRunningOperation operation(_("Reloading Defs"));

reloadDefs();
}
Expand Down
64 changes: 64 additions & 0 deletions radiant/ui/LongRunningOperationHandler.h
@@ -0,0 +1,64 @@
#pragma once

#include <functional>
#include "iradiant.h"
#include "imainframe.h"
#include "messages/LongRunningOperationMessage.h"

namespace ui
{

/**
* Listener class responding to LongRunningOperationMessages
* sent from the core routines. It will show a blocking dialog
* when any operation is started, and will hide that window
* once the last running operation is finished.
*/
class LongRunningOperationHandler
{
private:
std::size_t _level;

IScopedScreenUpdateBlockerPtr _blocker;

public:
LongRunningOperationHandler() :
_level(0)
{
GlobalRadiantCore().getMessageBus().addListener(
radiant::TypeListener<radiant::LongRunningOperationMessage>(
std::bind(&LongRunningOperationHandler::onMessage, this, std::placeholders::_1)
)
);
}

private:
void onMessage(radiant::LongRunningOperationMessage& message)
{
if (message.getType() == radiant::OperationEvent::Started)
{
std::string title = message.getTitle();

if (title.empty())
{
title = _("Operation in progress");
}

if (++_level == 1)
{
_blocker = GlobalMainFrame().getScopedScreenUpdateBlocker(title, std::string());
}
}
else if (message.getType() == radiant::OperationEvent::Finished)
{
assert(_level > 0);

if (_level > 0 && --_level == 0)
{
_blocker.reset();
}
}
}
};

}
2 changes: 2 additions & 0 deletions radiant/ui/UserInterfaceModule.cpp
Expand Up @@ -127,10 +127,12 @@ void UserInterfaceModule::initialiseModule(const ApplicationContext& ctx)
);

_eClassColourManager.reset(new EntityClassColourManager);
_longOperationHandler.reset(new LongRunningOperationHandler);
}

void UserInterfaceModule::shutdownModule()
{
_longOperationHandler.reset();
_eClassColourManager.reset();
}

Expand Down
2 changes: 2 additions & 0 deletions radiant/ui/UserInterfaceModule.h
Expand Up @@ -5,6 +5,7 @@
#include "icommandsystem.h"

#include "EntityClassColourManager.h"
#include "LongRunningOperationHandler.h"

namespace ui
{
Expand All @@ -21,6 +22,7 @@ class UserInterfaceModule :
{
private:
std::unique_ptr<EntityClassColourManager> _eClassColourManager;
std::unique_ptr<LongRunningOperationHandler> _longOperationHandler;

public:
// RegisterableModule
Expand Down
2 changes: 1 addition & 1 deletion radiant/ui/prefdialog/GameSetupDialog.h
Expand Up @@ -3,7 +3,7 @@
#include "icommandsystem.h"
#include "wxutil/dialog/DialogBase.h"
#include "GameSetupPage.h"
#include "GameConfigNeededMessage.h"
#include "messages/GameConfigNeededMessage.h"

class wxChoicebook;
class wxBookCtrlEvent;
Expand Down
2 changes: 1 addition & 1 deletion radiantcore/messagebus/MessageBus.h
Expand Up @@ -21,7 +21,7 @@ class MessageBus :
_nextId(1)
{}

std::size_t addListener(const Listener & listener) override
std::size_t addListener(const Listener& listener) override
{
std::lock_guard<std::recursive_mutex> guard(_lock);

Expand Down
2 changes: 1 addition & 1 deletion radiantcore/settings/GameManager.cpp
Expand Up @@ -22,7 +22,7 @@

#include "wxutil/dialog/MessageBox.h"
#include "module/StaticModule.h"
#include "GameConfigNeededMessage.h"
#include "messages/GameConfigNeededMessage.h"

#include <sigc++/bind.h>

Expand Down
1 change: 1 addition & 0 deletions tools/msvc/DarkRadiant.vcxproj
Expand Up @@ -1209,6 +1209,7 @@
<ClInclude Include="..\..\radiant\ui\filters\FiltersMainMenu.h" />
<ClInclude Include="..\..\radiant\ui\filters\FilterUserInterface.h" />
<ClInclude Include="..\..\radiant\ui\grid\GridUserInterface.h" />
<ClInclude Include="..\..\radiant\ui\LongRunningOperationHandler.h" />
<ClInclude Include="..\..\radiant\ui\mainframe\TopLevelFrame.h" />
<ClInclude Include="..\..\radiant\ui\mapinfo\LayerInfoTab.h" />
<ClInclude Include="..\..\radiant\ui\modelexport\ExportAsModelDialog.h" />
Expand Down
3 changes: 3 additions & 0 deletions tools/msvc/DarkRadiant.vcxproj.filters
Expand Up @@ -2811,6 +2811,9 @@
<ClInclude Include="..\..\radiant\ui\EntityClassColourManager.h">
<Filter>src\ui</Filter>
</ClInclude>
<ClInclude Include="..\..\radiant\ui\LongRunningOperationHandler.h">
<Filter>src\ui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\radiant\darkradiant.rc" />
Expand Down
4 changes: 3 additions & 1 deletion tools/msvc/libs.vcxproj
Expand Up @@ -151,12 +151,14 @@
<ClInclude Include="..\..\libs\eclass.h" />
<ClInclude Include="..\..\libs\entitylib.h" />
<ClInclude Include="..\..\libs\EventRateLimiter.h" />
<ClInclude Include="..\..\libs\GameConfigNeededMessage.h" />
<ClInclude Include="..\..\libs\GameConfigUtil.h" />
<ClInclude Include="..\..\libs\gamelib.h" />
<ClInclude Include="..\..\libs\generic\callback.h" />
<ClInclude Include="..\..\libs\KeyValueStore.h" />
<ClInclude Include="..\..\libs\maplib.h" />
<ClInclude Include="..\..\libs\messages\GameConfigNeededMessage.h" />
<ClInclude Include="..\..\libs\messages\LongRunningOperationMessage.h" />
<ClInclude Include="..\..\libs\messages\ScopedLongRunningOperation.h" />
<ClInclude Include="..\..\libs\ObservedSelectable.h" />
<ClInclude Include="..\..\libs\ObservedUndoable.h" />
<ClInclude Include="..\..\libs\os\dir.h" />
Expand Down
13 changes: 12 additions & 1 deletion tools/msvc/libs.vcxproj.filters
Expand Up @@ -185,7 +185,15 @@
</ClInclude>
<ClInclude Include="..\..\libs\maplib.h" />
<ClInclude Include="..\..\libs\GameConfigUtil.h" />
<ClInclude Include="..\..\libs\GameConfigNeededMessage.h" />
<ClInclude Include="..\..\libs\messages\LongRunningOperationMessage.h">
<Filter>messages</Filter>
</ClInclude>
<ClInclude Include="..\..\libs\messages\GameConfigNeededMessage.h">
<Filter>messages</Filter>
</ClInclude>
<ClInclude Include="..\..\libs\messages\ScopedLongRunningOperation.h">
<Filter>messages</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="util">
Expand Down Expand Up @@ -215,5 +223,8 @@
<Filter Include="generic">
<UniqueIdentifier>{ac492ec5-988b-4dd5-8b6f-a1a23fbd0ce0}</UniqueIdentifier>
</Filter>
<Filter Include="messages">
<UniqueIdentifier>{bc41bb46-8308-44d2-8380-e67d9e3945a6}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

0 comments on commit 4698288

Please sign in to comment.