/
MapFileProgressHandler.cpp
135 lines (114 loc) · 2.92 KB
/
MapFileProgressHandler.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include "MapFileProgressHandler.h"
#include "imap.h"
#include "iradiant.h"
#include "i18n.h"
#include <sigc++/functors/mem_fun.h>
#include "wxutil/ModalProgressDialog.h"
#include "wxutil/dialog/MessageBox.h"
#include "registry/registry.h"
#include "UserInterfaceModule.h"
namespace ui
{
MapFileProgressHandler::MapFileProgressHandler() :
_wasCancelled(false),
_level(0)
{
_msgSubscription = GlobalRadiantCore().getMessageBus().addListener(
radiant::IMessage::Type::MapFileOperation,
radiant::TypeListener<map::FileOperation>(
sigc::mem_fun(this, &MapFileProgressHandler::handleFileOperation)));
}
MapFileProgressHandler::~MapFileProgressHandler()
{
GlobalRadiantCore().getMessageBus().removeListener(_msgSubscription);
}
void MapFileProgressHandler::dispatchWithLockAndCatch(const std::function<void()>& function)
{
GetUserInterfaceModule().dispatch([function, this] ()
{
std::lock_guard<std::mutex> lock(_lock);
try
{
// Any updates to the _blocker instance might throw an OperationAbortedException
function();
}
catch (const wxutil::ModalProgressDialog::OperationAbortedException&)
{
// We're in the UI thread, so destroy the dialog right here
_blocker.reset();
// Remember that we got cancelled, next time a message is incoming,
// we will signal this to the caller
_wasCancelled = true;
}
});
}
void MapFileProgressHandler::handleFileOperation(map::FileOperation& msg)
{
auto lock = std::make_unique< std::lock_guard<std::mutex> >(_lock);
// A previous _blocker update might indicate a cancel operation, propagate this info
if (_wasCancelled)
{
_wasCancelled = false;
msg.cancelOperation();
return;
}
switch (msg.getMessageType())
{
case map::FileOperation::Started:
{
auto title = msg.getOperationType() == map::FileOperation::Type::Export ?
_("Writing map") : _("Loading map");
if (++_level == 1)
{
dispatchWithLockAndCatch([title, this]()
{
// Level might have been decreased in the meantime, check it
if (_level > 0 && GlobalMainFrame().isActiveApp() &&
!registry::getValue<bool>(RKEY_MAP_SUPPRESS_LOAD_STATUS_DIALOG))
{
_blocker.reset(new ScreenUpdateBlocker(title, _("Processing..."), true));
}
});
}
}
break;
case map::FileOperation::Progress:
{
if (!_blocker || _level == 0) break;
auto text = msg.getText();
if (msg.canCalculateProgress())
{
auto fraction = msg.getProgressFraction();
dispatchWithLockAndCatch([text, fraction, this]()
{
_blocker->setMessageAndProgress(text, fraction);
});
}
else
{
dispatchWithLockAndCatch([text, this]()
{
_blocker->setMessage(text);
_blocker->pulse();
});
}
}
break;
case map::FileOperation::Finished:
{
assert(_level > 0);
if (_level > 0 && --_level == 0)
{
dispatchWithLockAndCatch([this]()
{
_blocker.reset();
});
}
break;
}
};
// Release the lock, and give the UI a chance to process
lock.reset();
wxTheApp->Yield();
}
}