mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-23 18:06:26 -07:00
Define Cockatrice as an editor/handler for .cod files and cockatrice:// protocol on all platforms (#6775)
* [Application] Add single instance guard and mime types. Took 2 hours 39 minutes Took 18 minutes Took 5 minutes Took 12 seconds Took 11 seconds * Rework Took 30 minutes Took 50 seconds * Only enforce single instance if launched with arguments. Took 5 minutes * Prototype intents Took 53 minutes Took 6 seconds * Connect/disconnect and join game/room intents. Took 3 hours 14 minutes Took 2 seconds Took 15 seconds * Fix include. Took 1 minute Took 23 seconds Took 2 seconds * Mac handling. Took 10 minutes Took 12 seconds Took 3 minutes * Lint. Took 3 minutes * Rebase. Took 3 minutes Took 17 seconds * Implement UrlSchemeEventFilter Took 10 minutes Took 7 seconds * Qt Moc Took 3 minutes * Modern PList. Took 21 minutes Took 1 minute * Debug output. Took 6 minutes Took 19 minutes * Watch file:// prefix. Took 15 minutes Took 7 seconds * Better handler. Took 6 minutes * Don't store reference in member Took 5 minutes * Move impl to cpp, fix lifetime issues. Took 11 minutes Took 2 minutes * Better single-instance handoff, url intent harded copy game link context-menu Polish for installers Took 35 minutes Took 8 seconds --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
27fb5e51de
commit
59d90db3c7
43 changed files with 1372 additions and 13 deletions
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef COCKATRICE_CONTEXT_CONNECT_TO_SERVER_H
|
||||
#define COCKATRICE_CONTEXT_CONNECT_TO_SERVER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
struct ContextConnectToServer
|
||||
{
|
||||
QString hostname;
|
||||
QString port;
|
||||
QString username;
|
||||
QString password;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_CONTEXT_CONNECT_TO_SERVER_H
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef COCKATRICE_CONTEXT_JOIN_GAME_H
|
||||
#define COCKATRICE_CONTEXT_JOIN_GAME_H
|
||||
#include "context_join_room.h"
|
||||
|
||||
struct ContextJoinGame
|
||||
{
|
||||
ContextJoinRoom roomContext;
|
||||
int gameId;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_CONTEXT_JOIN_GAME_H
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef COCKATRICE_CONTEXT_JOIN_ROOM_H
|
||||
#define COCKATRICE_CONTEXT_JOIN_ROOM_H
|
||||
|
||||
#include "context_connect_to_server.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
struct ContextJoinRoom
|
||||
{
|
||||
ContextConnectToServer serverContext;
|
||||
int roomId;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_CONTEXT_JOIN_ROOM_H
|
||||
48
cockatrice/src/interface/intents/intent.cpp
Normal file
48
cockatrice/src/interface/intents/intent.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include "intent.h"
|
||||
|
||||
Intent::Intent(QObject *parent) : QObject(parent)
|
||||
{
|
||||
// An intent is done as soon as it reports success or failure. Deleting it
|
||||
// also tears down its dependency chain and disconnects any signal wiring.
|
||||
connect(this, &Intent::finished, this, &QObject::deleteLater);
|
||||
connect(this, &Intent::failed, this, &QObject::deleteLater);
|
||||
}
|
||||
|
||||
Intent::~Intent() = default;
|
||||
|
||||
void Intent::execute()
|
||||
{
|
||||
if (checkPrecondition()) {
|
||||
onPreconditionSatisfied();
|
||||
} else {
|
||||
onPreconditionNotSatisfied();
|
||||
}
|
||||
}
|
||||
|
||||
void Intent::runDependency(Intent *dependency)
|
||||
{
|
||||
dependency->setParent(this);
|
||||
connect(dependency, &Intent::finished, this, [this]() {
|
||||
// Re-check after dependency finishes
|
||||
this->execute();
|
||||
});
|
||||
connect(dependency, &Intent::failed, this, &Intent::failed);
|
||||
|
||||
dependency->execute();
|
||||
}
|
||||
|
||||
void Intent::emitFinished()
|
||||
{
|
||||
if (!completed) {
|
||||
completed = true;
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
|
||||
void Intent::emitFailed(const QString &reason)
|
||||
{
|
||||
if (!completed) {
|
||||
completed = true;
|
||||
emit failed(reason);
|
||||
}
|
||||
}
|
||||
37
cockatrice/src/interface/intents/intent.h
Normal file
37
cockatrice/src/interface/intents/intent.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef COCKATRICE_INTENT_H
|
||||
#define COCKATRICE_INTENT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Intent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Intent(QObject *parent = nullptr);
|
||||
~Intent() override;
|
||||
|
||||
void execute();
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
void failed(QString reason);
|
||||
|
||||
protected:
|
||||
// --- Subclasses must implement these ---
|
||||
virtual bool checkPrecondition() const = 0;
|
||||
virtual void onPreconditionSatisfied() = 0;
|
||||
virtual void onPreconditionNotSatisfied() = 0;
|
||||
|
||||
// Helper to chain another intent
|
||||
void runDependency(Intent *dependency);
|
||||
|
||||
// Emit the outcome exactly once; ignore late signals after the intent is done.
|
||||
void emitFinished();
|
||||
void emitFailed(const QString &reason);
|
||||
|
||||
private:
|
||||
bool completed = false;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_H
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#include "intent_connect_to_server.h"
|
||||
|
||||
#include "intent_disconnect_from_server.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
IntentConnectToServer::IntentConnectToServer(RemoteClient *_remoteClient, ContextConnectToServer *_context)
|
||||
: Intent(), remoteClient(_remoteClient), context(_context)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentConnectToServer::checkPrecondition() const
|
||||
{
|
||||
return remoteClient->getStatus() == ClientStatus::StatusDisconnected;
|
||||
}
|
||||
|
||||
void IntentConnectToServer::onPreconditionSatisfied()
|
||||
{
|
||||
remoteClient->connectToServer(context->hostname, context->port.toUInt(), context->username, context->password);
|
||||
connect(remoteClient, &RemoteClient::statusChanged, this, &IntentConnectToServer::onStatusChanged);
|
||||
connect(remoteClient, &RemoteClient::socketError, this, &IntentConnectToServer::onSocketError);
|
||||
connect(
|
||||
remoteClient, &RemoteClient::loginError, this,
|
||||
[this](Response::ResponseCode, const QString &reason, quint32, const QList<QString> &) { emitFailed(reason); });
|
||||
|
||||
QTimer::singleShot(15000, this, [this]() {
|
||||
emitFailed(tr("Timed out while connecting to %1:%2").arg(context->hostname, context->port));
|
||||
});
|
||||
}
|
||||
|
||||
void IntentConnectToServer::onPreconditionNotSatisfied()
|
||||
{
|
||||
runDependency(new IntentDisconnectFromServer(remoteClient));
|
||||
}
|
||||
|
||||
void IntentConnectToServer::onStatusChanged(ClientStatus status)
|
||||
{
|
||||
if (status == ClientStatus::StatusLoggedIn) {
|
||||
emitFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void IntentConnectToServer::onSocketError(const QString &errorString)
|
||||
{
|
||||
emitFailed(tr("Failed to connect to %1:%2: %3").arg(context->hostname, context->port, errorString));
|
||||
}
|
||||
29
cockatrice/src/interface/intents/intent_connect_to_server.h
Normal file
29
cockatrice/src/interface/intents/intent_connect_to_server.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef COCKATRICE_INTENT_CONNECT_TO_SERVER_H
|
||||
#define COCKATRICE_INTENT_CONNECT_TO_SERVER_H
|
||||
|
||||
#include "contexts/context_connect_to_server.h"
|
||||
#include "intent.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
class IntentConnectToServer : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentConnectToServer(RemoteClient *_remoteClient, ContextConnectToServer *_context);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
RemoteClient *remoteClient;
|
||||
ContextConnectToServer *context;
|
||||
|
||||
private slots:
|
||||
void onStatusChanged(ClientStatus status);
|
||||
void onSocketError(const QString &errorString);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_CONNECT_TO_SERVER_H
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#include "intent_disconnect_from_server.h"
|
||||
|
||||
IntentDisconnectFromServer::IntentDisconnectFromServer(RemoteClient *_remoteClient)
|
||||
: Intent(), remoteClient(_remoteClient)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentDisconnectFromServer::checkPrecondition() const
|
||||
{
|
||||
return remoteClient->getStatus() == ClientStatus::StatusDisconnected;
|
||||
}
|
||||
|
||||
void IntentDisconnectFromServer::onPreconditionSatisfied()
|
||||
{
|
||||
emitFinished();
|
||||
}
|
||||
|
||||
void IntentDisconnectFromServer::onPreconditionNotSatisfied()
|
||||
{
|
||||
connect(remoteClient, &RemoteClient::statusChanged, this, &IntentDisconnectFromServer::onStatusChanged);
|
||||
remoteClient->disconnectFromServer();
|
||||
}
|
||||
|
||||
void IntentDisconnectFromServer::onStatusChanged(ClientStatus status)
|
||||
{
|
||||
if (status == ClientStatus::StatusDisconnected) {
|
||||
emitFinished();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef COCKATRICE_INTENT_DISCONNECT_FROM_SERVER_H
|
||||
#define COCKATRICE_INTENT_DISCONNECT_FROM_SERVER_H
|
||||
|
||||
#include "intent.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
class IntentDisconnectFromServer : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentDisconnectFromServer(RemoteClient *_remoteClient);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
RemoteClient *remoteClient;
|
||||
|
||||
private slots:
|
||||
void onStatusChanged(ClientStatus status);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_DISCONNECT_FROM_SERVER_H
|
||||
76
cockatrice/src/interface/intents/intent_join_server_game.cpp
Normal file
76
cockatrice/src/interface/intents/intent_join_server_game.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#include "intent_join_server_game.h"
|
||||
|
||||
#include "../widgets/server/game_selector.h"
|
||||
#include "../widgets/tabs/tab_room.h"
|
||||
#include "../widgets/tabs/tab_supervisor.h"
|
||||
#include "intent_join_server_room.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
IntentJoinServerGame::IntentJoinServerGame(TabSupervisor *_tabSupervisor,
|
||||
RemoteClient *_remoteClient,
|
||||
std::unique_ptr<ContextJoinGame> _context)
|
||||
: Intent(), tabSupervisor(_tabSupervisor), remoteClient(_remoteClient), context(_context.release())
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentJoinServerGame::checkPrecondition() const
|
||||
{
|
||||
if (remoteClient->getStatus() != ClientStatus::StatusLoggedIn) {
|
||||
return false;
|
||||
}
|
||||
// peerPort() reflects the actual TCP peer, which may differ from the
|
||||
// configured server port (e.g. when connecting through a proxy), so only
|
||||
// the hostname is compared here.
|
||||
if (remoteClient->peerName() != context->roomContext.serverContext.hostname) {
|
||||
return false;
|
||||
}
|
||||
if (QString::number(remoteClient->peerPort()) != context->roomContext.serverContext.port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tabSupervisor->getRoomTabs().contains(context->roomContext.roomId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IntentJoinServerGame::onPreconditionSatisfied()
|
||||
{
|
||||
TabRoom *room = tabSupervisor->getRoomTabs().value(context->roomContext.roomId);
|
||||
if (!tryJoinGame(room)) {
|
||||
waitForGame(room);
|
||||
}
|
||||
}
|
||||
|
||||
void IntentJoinServerGame::onPreconditionNotSatisfied()
|
||||
{
|
||||
runDependency(new IntentJoinServerRoom(tabSupervisor, remoteClient, &context->roomContext));
|
||||
}
|
||||
|
||||
bool IntentJoinServerGame::tryJoinGame(TabRoom *room)
|
||||
{
|
||||
if (!room) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (room->getGameSelector()->joinGameById(context->gameId)) {
|
||||
emitFinished();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntentJoinServerGame::waitForGame(TabRoom *room)
|
||||
{
|
||||
connect(room, &TabRoom::gameListUpdated, this, [this]() {
|
||||
TabRoom *updatedRoom = tabSupervisor->getRoomTabs().value(context->roomContext.roomId);
|
||||
if (updatedRoom) {
|
||||
tryJoinGame(updatedRoom);
|
||||
}
|
||||
});
|
||||
|
||||
QTimer::singleShot(15000, this, [this]() { emitFailed(tr("Game %1 not found in the room").arg(context->gameId)); });
|
||||
}
|
||||
37
cockatrice/src/interface/intents/intent_join_server_game.h
Normal file
37
cockatrice/src/interface/intents/intent_join_server_game.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef COCKATRICE_INTENT_JOIN_SERVER_GAME_H
|
||||
#define COCKATRICE_INTENT_JOIN_SERVER_GAME_H
|
||||
|
||||
#include "contexts/context_join_game.h"
|
||||
#include "intent.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include <memory>
|
||||
|
||||
class TabRoom;
|
||||
class TabSupervisor;
|
||||
|
||||
class IntentJoinServerGame : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentJoinServerGame(TabSupervisor *_tabSupervisor,
|
||||
RemoteClient *_remoteClient,
|
||||
std::unique_ptr<ContextJoinGame> _context);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
bool tryJoinGame(TabRoom *room);
|
||||
void waitForGame(TabRoom *room);
|
||||
|
||||
TabSupervisor *tabSupervisor;
|
||||
RemoteClient *remoteClient;
|
||||
QScopedPointer<ContextJoinGame> context;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_JOIN_SERVER_GAME_H
|
||||
74
cockatrice/src/interface/intents/intent_join_server_room.cpp
Normal file
74
cockatrice/src/interface/intents/intent_join_server_room.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#include "intent_join_server_room.h"
|
||||
|
||||
#include "../widgets/tabs/tab_room.h"
|
||||
#include "../widgets/tabs/tab_server.h"
|
||||
#include "../widgets/tabs/tab_supervisor.h"
|
||||
#include "intent_connect_to_server.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_room.pb.h>
|
||||
|
||||
IntentJoinServerRoom::IntentJoinServerRoom(TabSupervisor *_tabSupervisor,
|
||||
RemoteClient *_remoteClient,
|
||||
ContextJoinRoom *_context)
|
||||
: Intent(), tabSupervisor(_tabSupervisor), remoteClient(_remoteClient), context(_context)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentJoinServerRoom::checkPrecondition() const
|
||||
{
|
||||
if (remoteClient->getStatus() != ClientStatus::StatusLoggedIn) {
|
||||
return false;
|
||||
}
|
||||
// peerPort() reflects the actual TCP peer, which may differ from the
|
||||
// configured server port (e.g. when connecting through a proxy), so only
|
||||
// the hostname is compared here.
|
||||
if (remoteClient->peerName() != context->serverContext.hostname) {
|
||||
return false;
|
||||
}
|
||||
if (QString::number(remoteClient->peerPort()) != context->serverContext.port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IntentJoinServerRoom::onPreconditionSatisfied()
|
||||
{
|
||||
if (tabSupervisor->getRoomTabs().contains(context->roomId)) {
|
||||
tabSupervisor->setCurrentWidget(tabSupervisor->getRoomTabs().value(context->roomId));
|
||||
emitFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
TabServer *tabServer = tabSupervisor->getTabServer();
|
||||
if (!tabServer) {
|
||||
tabSupervisor->openTabServer();
|
||||
tabServer = tabSupervisor->getTabServer();
|
||||
}
|
||||
if (!tabServer) {
|
||||
emitFailed(tr("No server tab available"));
|
||||
return;
|
||||
}
|
||||
|
||||
const int roomId = context->roomId;
|
||||
tabServer->joinRoom(roomId, true);
|
||||
connect(tabServer, &TabServer::roomJoined, this, [this, roomId](const ServerInfo_Room &info, bool) {
|
||||
if (info.room_id() == roomId) {
|
||||
emitFinished();
|
||||
}
|
||||
});
|
||||
connect(tabServer, &TabServer::roomJoinFailed, this, [this, roomId](int failedRoomId) {
|
||||
if (failedRoomId == roomId) {
|
||||
emitFailed(tr("Failed to join the server room %1").arg(roomId));
|
||||
}
|
||||
});
|
||||
|
||||
QTimer::singleShot(15000, this,
|
||||
[this, roomId]() { emitFailed(tr("Timed out while joining the server room %1").arg(roomId)); });
|
||||
}
|
||||
|
||||
void IntentJoinServerRoom::onPreconditionNotSatisfied()
|
||||
{
|
||||
runDependency(new IntentConnectToServer(remoteClient, &context->serverContext));
|
||||
}
|
||||
28
cockatrice/src/interface/intents/intent_join_server_room.h
Normal file
28
cockatrice/src/interface/intents/intent_join_server_room.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef COCKATRICE_INTENT_JOIN_SERVER_ROOM_H
|
||||
#define COCKATRICE_INTENT_JOIN_SERVER_ROOM_H
|
||||
|
||||
#include "contexts/context_join_room.h"
|
||||
#include "intent.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
class TabSupervisor;
|
||||
|
||||
class IntentJoinServerRoom : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentJoinServerRoom(TabSupervisor *_tabSupervisor, RemoteClient *_remoteClient, ContextJoinRoom *_context);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
TabSupervisor *tabSupervisor;
|
||||
RemoteClient *remoteClient;
|
||||
ContextJoinRoom *context;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_JOIN_SERVER_ROOM_H
|
||||
33
cockatrice/src/interface/intents/intent_login.cpp
Normal file
33
cockatrice/src/interface/intents/intent_login.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include "intent_login.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "libcockatrice/settings/servers_settings.h"
|
||||
|
||||
IntentGetLoginCredentials::IntentGetLoginCredentials(ContextConnectToServer *_context) : Intent(), context(_context)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentGetLoginCredentials::checkPrecondition() const
|
||||
{
|
||||
ServersSettings &servers = SettingsCache::instance().servers();
|
||||
return servers.hasLoginData(context->hostname, context->port);
|
||||
}
|
||||
|
||||
void IntentGetLoginCredentials::onPreconditionSatisfied()
|
||||
{
|
||||
ServersSettings &servers = SettingsCache::instance().servers();
|
||||
const int index = servers.findServerIndex(context->hostname, context->port);
|
||||
|
||||
if (index >= 0) {
|
||||
context->username = servers.getValue(QString("username%1").arg(index), "server", "server_details").toString();
|
||||
context->password = servers.getValue(QString("password%1").arg(index), "server", "server_details").toString();
|
||||
emitFinished();
|
||||
} else {
|
||||
emitFailed(tr("No saved credentials for this server"));
|
||||
}
|
||||
}
|
||||
|
||||
void IntentGetLoginCredentials::onPreconditionNotSatisfied()
|
||||
{
|
||||
emitFailed(tr("No saved credentials for this server"));
|
||||
}
|
||||
23
cockatrice/src/interface/intents/intent_login.h
Normal file
23
cockatrice/src/interface/intents/intent_login.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef COCKATRICE_INTENT_LOGIN_H
|
||||
#define COCKATRICE_INTENT_LOGIN_H
|
||||
|
||||
#include "contexts/context_connect_to_server.h"
|
||||
#include "intent.h"
|
||||
|
||||
class IntentGetLoginCredentials : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentGetLoginCredentials(ContextConnectToServer *_context);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
ContextConnectToServer *context;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_LOGIN_H
|
||||
34
cockatrice/src/interface/intents/intent_open_local_deck.cpp
Normal file
34
cockatrice/src/interface/intents/intent_open_local_deck.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include "intent_open_local_deck.h"
|
||||
|
||||
#include "../deck_loader/deck_file_format.h"
|
||||
#include "../deck_loader/deck_loader.h"
|
||||
#include "../widgets/tabs/tab_supervisor.h"
|
||||
#include "intent_wait_for_database_load.h"
|
||||
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
||||
IntentOpenLocalDeck::IntentOpenLocalDeck(TabSupervisor *_tabSupervisor, const QString &_file)
|
||||
: Intent(), tabSupervisor(_tabSupervisor), file(_file)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentOpenLocalDeck::checkPrecondition() const
|
||||
{
|
||||
return CardDatabaseManager::getInstance()->getLoadStatus() == LoadStatus::Ok;
|
||||
}
|
||||
|
||||
void IntentOpenLocalDeck::onPreconditionSatisfied()
|
||||
{
|
||||
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(file, DeckFileFormat::getFormatFromName(file), true);
|
||||
if (deckOpt) {
|
||||
tabSupervisor->openDeckInNewTab(deckOpt.value());
|
||||
emitFinished();
|
||||
} else {
|
||||
emitFailed(tr("Unable to load deck file %1").arg(file));
|
||||
}
|
||||
}
|
||||
|
||||
void IntentOpenLocalDeck::onPreconditionNotSatisfied()
|
||||
{
|
||||
runDependency(new IntentWaitForDatabaseLoad);
|
||||
}
|
||||
27
cockatrice/src/interface/intents/intent_open_local_deck.h
Normal file
27
cockatrice/src/interface/intents/intent_open_local_deck.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef COCKATRICE_INTENT_OPEN_LOCAL_DECK_H
|
||||
#define COCKATRICE_INTENT_OPEN_LOCAL_DECK_H
|
||||
|
||||
#include "intent.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class TabSupervisor;
|
||||
|
||||
class IntentOpenLocalDeck : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentOpenLocalDeck(TabSupervisor *_tabSupervisor, const QString &_file);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
TabSupervisor *tabSupervisor;
|
||||
QString file;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_OPEN_LOCAL_DECK_H
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#include "intent_wait_for_database_load.h"
|
||||
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
||||
bool IntentWaitForDatabaseLoad::checkPrecondition() const
|
||||
{
|
||||
return CardDatabaseManager::getInstance()->getLoadStatus() == LoadStatus::Ok;
|
||||
}
|
||||
|
||||
void IntentWaitForDatabaseLoad::onPreconditionSatisfied()
|
||||
{
|
||||
emitFinished();
|
||||
}
|
||||
|
||||
void IntentWaitForDatabaseLoad::onPreconditionNotSatisfied()
|
||||
{
|
||||
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
|
||||
[this]() { emitFinished(); });
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef COCKATRICE_INTENT_WAIT_FOR_DATABASE_LOAD_H
|
||||
#define COCKATRICE_INTENT_WAIT_FOR_DATABASE_LOAD_H
|
||||
|
||||
#include "intent.h"
|
||||
|
||||
class IntentWaitForDatabaseLoad : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_WAIT_FOR_DATABASE_LOAD_H
|
||||
89
cockatrice/src/interface/intents/url_parser.cpp
Normal file
89
cockatrice/src/interface/intents/url_parser.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#include "url_parser.h"
|
||||
|
||||
#include "../window_main.h"
|
||||
#include "contexts/context_join_game.h"
|
||||
#include "intent_join_server_game.h"
|
||||
#include "intent_login.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
#include <memory>
|
||||
|
||||
IntentUrlParser::IntentUrlParser(QObject *parent, MainWindow *_mainWindow) : QObject(parent), mainWindow(_mainWindow)
|
||||
{
|
||||
}
|
||||
|
||||
void IntentUrlParser::handle(const QString &urlStr)
|
||||
{
|
||||
QUrl url(urlStr);
|
||||
|
||||
if (url.scheme() != "cockatrice") {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString action = url.host();
|
||||
QUrlQuery query(url);
|
||||
|
||||
if (action == "joingame") {
|
||||
handleJoinGame(query);
|
||||
} else if (action == "opendeck") {
|
||||
// handleOpenDeck(query);
|
||||
} else {
|
||||
qWarning() << "Unknown intent:" << action;
|
||||
}
|
||||
}
|
||||
|
||||
void IntentUrlParser::handleJoinGame(const QUrlQuery &query)
|
||||
{
|
||||
auto showError = [this](const QString &message) { QMessageBox::warning(mainWindow, tr("Open game"), message); };
|
||||
|
||||
auto ctx = std::make_unique<ContextJoinGame>();
|
||||
|
||||
ctx->roomContext.serverContext.hostname = query.queryItemValue("hostname");
|
||||
ctx->roomContext.serverContext.port = query.queryItemValue("port");
|
||||
|
||||
if (ctx->roomContext.serverContext.hostname.isEmpty()) {
|
||||
showError(tr("Missing or empty hostname in the game link"));
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
ctx->roomContext.serverContext.port.toUShort(&ok);
|
||||
if (!ok) {
|
||||
showError(tr("Invalid or missing port in the game link"));
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->roomContext.roomId = query.queryItemValue("roomid").toInt(&ok);
|
||||
|
||||
if (!ok) {
|
||||
showError(tr("Invalid or missing room id in the game link"));
|
||||
return;
|
||||
}
|
||||
|
||||
ok = false;
|
||||
ctx->gameId = query.queryItemValue("gameid").toInt(&ok);
|
||||
|
||||
if (!ok) {
|
||||
showError(tr("Invalid or missing game id in the game link"));
|
||||
return;
|
||||
}
|
||||
|
||||
// The join game intent owns the context and the credential lookup; once the
|
||||
// chain finishes (or fails) it deletes the whole tree.
|
||||
ContextConnectToServer *serverContext = &ctx->roomContext.serverContext;
|
||||
auto joinGameIntent =
|
||||
new IntentJoinServerGame(mainWindow->getTabSupervisor(), mainWindow->getRemoteClient(), std::move(ctx));
|
||||
joinGameIntent->setParent(this);
|
||||
|
||||
auto getLoginCredentialsIntent = new IntentGetLoginCredentials(serverContext);
|
||||
getLoginCredentialsIntent->setParent(joinGameIntent);
|
||||
|
||||
connect(getLoginCredentialsIntent, &Intent::finished, joinGameIntent, &Intent::execute);
|
||||
connect(getLoginCredentialsIntent, &Intent::failed, joinGameIntent, &Intent::failed);
|
||||
connect(joinGameIntent, &Intent::failed, this, [showError](const QString &reason) { showError(reason); });
|
||||
|
||||
getLoginCredentialsIntent->execute();
|
||||
}
|
||||
20
cockatrice/src/interface/intents/url_parser.h
Normal file
20
cockatrice/src/interface/intents/url_parser.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef COCKATRICE_URL_PARSER_H
|
||||
#define COCKATRICE_URL_PARSER_H
|
||||
#include <QObject>
|
||||
#include <QUrlQuery>
|
||||
|
||||
class MainWindow;
|
||||
class IntentUrlParser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentUrlParser(QObject *parent, MainWindow *mainWindow);
|
||||
void handle(const QString &urlStr);
|
||||
void handleJoinGame(const QUrlQuery &query);
|
||||
|
||||
private:
|
||||
MainWindow *mainWindow;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_URL_PARSER_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue