Skip to content

Commit

Permalink
#5761: Copy command is now sending an operation message to give feedb…
Browse files Browse the repository at this point in the history
…ack in the status bar
  • Loading branch information
codereader committed Apr 3, 2022
1 parent d9f8b63 commit 9e33286
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 3 deletions.
11 changes: 10 additions & 1 deletion radiantcore/selection/clipboard/Clipboard.cpp
Expand Up @@ -14,8 +14,9 @@
#include "map/algorithm/Import.h"
#include "selection/algorithm/General.h"
#include "selection/algorithm/Transformation.h"
#include "command/ExecutionNotPossible.h"
#include "command/ExecutionFailure.h"
#include "command/ExecutionNotPossible.h"
#include "messages/MapOperationMessage.h"

namespace selection
{
Expand Down Expand Up @@ -43,6 +44,12 @@ void copy(const cmd::ArgumentList& args)
throw cmd::ExecutionNotPossible(_("No clipboard module attached, cannot perform this action."));
}

if (GlobalSelectionSystem().countSelected() == 0)
{
map::OperationMessage::Send(_("Cannot copy, nothing selected"));
return;
}

// When exporting to the system clipboard, use the portable format
auto format = GlobalMapFormatManager().getMapFormatByName(map::PORTABLE_MAP_FORMAT_NAME);

Expand All @@ -52,6 +59,8 @@ void copy(const cmd::ArgumentList& args)

// Copy the resulting string to the clipboard
GlobalClipboard().setString(out.str());

map::OperationMessage::Send(_("Selection copied to Clipboard"));
}
else
{
Expand Down
29 changes: 27 additions & 2 deletions test/Selection.cpp
Expand Up @@ -22,6 +22,8 @@
#include "registry/registry.h"
#include "algorithm/View.h"
#include "testutil/CommandFailureHelper.h"
#include "testutil/MapOperationMonitor.h"
#include "algorithm/XmlUtils.h"

namespace test
{
Expand Down Expand Up @@ -498,13 +500,36 @@ TEST_F(ClipboardTest, CopyEmptySelection)
{
EXPECT_EQ(GlobalSelectionSystem().countSelected(), 0) << "Should start with an empty selection";

// Monitor radiant to catch the CommandExecutionFailedMessage
// Monitor radiant to catch the messages
CommandFailureHelper helper;
MapOperationMonitor operationMonitor;

// This should do nothing, and it should not throw any execution failures neither
GlobalCommandSystem().executeCommand("Copy");

EXPECT_FALSE(helper.messageReceived()) << "Command execution should have failed";
EXPECT_FALSE(helper.messageReceived()) << "Command execution shouldn't have failed";
EXPECT_TRUE(operationMonitor.messageReceived()) << "Command should have sent out an OperationMessage";
}

TEST_F(ClipboardTest, CopyNonEmptySelection)
{
auto worldspawn = GlobalMapModule().findOrInsertWorldspawn();
auto brush = algorithm::createCubicBrush(worldspawn);

Node_setSelected(brush, true);

// Monitor radiant to catch the messages
CommandFailureHelper helper;
MapOperationMonitor operationMonitor;

// This should do nothing, and it should not throw any execution failures neither
GlobalCommandSystem().executeCommand("Copy");

EXPECT_FALSE(helper.messageReceived()) << "Command execution should not have failed";
EXPECT_TRUE(operationMonitor.messageReceived()) << "Command should have sent out an OperationMessage";

// Check the clipboard contents, it should contain a mapx file
algorithm::assertStringIsMapxFile(GlobalClipboard().getString());
}

}
49 changes: 49 additions & 0 deletions test/testutil/MapOperationMonitor.h
@@ -0,0 +1,49 @@
#pragma once

#include "imessagebus.h"
#include "iradiant.h"
#include "messages/MapOperationMessage.h"

namespace test
{

// Listens for MapOperationMessages
class MapOperationMonitor
{
private:
std::size_t _msgSubscription;
bool _messageReceived;
std::string _lastReceivedMessage;

public:
MapOperationMonitor() :
_messageReceived(false)
{
// Subscribe to the event asking for the target path
_msgSubscription = GlobalRadiantCore().getMessageBus().addListener(
radiant::IMessage::Type::MapOperationFinished,
radiant::TypeListener<map::OperationMessage>(
[this](map::OperationMessage& msg)
{
_messageReceived = true;
_lastReceivedMessage = msg.getMessage();
}));
}

bool messageReceived() const
{
return _messageReceived;
}

const std::string& getLastReceivedMessage() const
{
return _lastReceivedMessage;
}

~MapOperationMonitor()
{
GlobalRadiantCore().getMessageBus().removeListener(_msgSubscription);
}
};

}
1 change: 1 addition & 0 deletions tools/msvc/Tests/Tests.vcxproj
Expand Up @@ -73,6 +73,7 @@
<ClInclude Include="..\..\..\test\TestContext.h" />
<ClInclude Include="..\..\..\test\TestLogFile.h" />
<ClInclude Include="..\..\..\test\testutil\CommandFailureHelper.h" />
<ClInclude Include="..\..\..\test\testutil\MapOperationMonitor.h" />
<ClInclude Include="..\..\..\test\testutil\TestBufferObjectProvider.h" />
<ClInclude Include="..\..\..\test\testutil\FileSelectionHelper.h" />
</ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions tools/msvc/Tests/Tests.vcxproj.filters
Expand Up @@ -93,6 +93,9 @@
<Filter>testutil</Filter>
</ClInclude>
<ClInclude Include="..\..\..\test\FakeClipboardModule.h" />
<ClInclude Include="..\..\..\test\testutil\MapOperationMonitor.h">
<Filter>testutil</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="algorithm">
Expand Down

0 comments on commit 9e33286

Please sign in to comment.