/*
* The Mana Client
* Copyright (C) 2010-2012 The Mana Developers
*
* This file is part of The Mana Client.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "gui/socialwindow.h"
#include "client.h"
#include "event.h"
#include "guild.h"
#include "localplayer.h"
#include "party.h"
#include "gui/confirmdialog.h"
#include "gui/okdialog.h"
#include "gui/setup.h"
#include "gui/textdialog.h"
#include "gui/widgets/avatarlistbox.h"
#include "gui/widgets/browserbox.h"
#include "gui/widgets/button.h"
#include "gui/widgets/linkhandler.h"
#include "gui/widgets/popup.h"
#include "gui/widgets/scrollarea.h"
#include "gui/widgets/tab.h"
#include "gui/widgets/tabbedarea.h"
#include "net/net.h"
#include "net/chathandler.h"
#include "net/guildhandler.h"
#include "net/partyhandler.h"
#include "resources/theme.h"
#include "utils/gettext.h"
#include "utils/stringutils.h"
#include
class SocialTab : public Tab
{
protected:
friend class SocialWindow;
SocialTab() = default;
~SocialTab() override
{
// Cleanup dialogs
if (mInviteDialog)
{
mInviteDialog->close();
mInviteDialog->scheduleDelete();
mInviteDialog = nullptr;
}
if (mConfirmDialog)
{
mConfirmDialog->close();
mConfirmDialog->scheduleDelete();
mConfirmDialog = nullptr;
}
}
virtual void invite() = 0;
virtual void leave() = 0;
TextDialog *mInviteDialog = nullptr;
ConfirmDialog *mConfirmDialog = nullptr;
std::unique_ptr mScroll;
std::unique_ptr mList;
};
class GuildTab : public SocialTab, public gcn::ActionListener
{
public:
GuildTab(Guild *guild):
mGuild(guild)
{
setCaption(guild->getName());
setTabColor(&Theme::getThemeColor(Theme::GUILD));
mList = std::make_unique(guild);
mScroll = std::make_unique(mList.get());
mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_AUTO);
}
void action(const gcn::ActionEvent &event) override
{
if (event.getId() == "do invite")
{
std::string name = mInviteDialog->getText();
if (!name.empty())
{
Net::getGuildHandler()->invite(mGuild->getId(), name);
serverNotice(strprintf(_("Invited user %s to guild %s."),
name.c_str(),
mGuild->getName().c_str()));
}
mInviteDialog = nullptr;
}
else if (event.getId() == "~do invite")
{
mInviteDialog = nullptr;
}
else if (event.getId() == "yes")
{
Net::getGuildHandler()->leave(mGuild->getId());
serverNotice(strprintf(_("Guild %s quit requested."),
mGuild->getName().c_str()));
mConfirmDialog = nullptr;
}
else if (event.getId() == "no")
{
mConfirmDialog = nullptr;
}
}
protected:
void invite() override
{
// TODO - Give feedback on whether the invite succeeded
mInviteDialog = new TextDialog(_("Member Invite to Guild"),
strprintf(_("Who would you like to invite to guild %s?"),
mGuild->getName().c_str()),
socialWindow, true);
mInviteDialog->setActionEventId("do invite");
mInviteDialog->addActionListener(this);
}
void leave() override
{
mConfirmDialog = new ConfirmDialog(_("Leave Guild?"),
strprintf(_("Are you sure you want to leave guild %s?"),
mGuild->getName().c_str()),
socialWindow);
mConfirmDialog->addActionListener(this);
}
private:
Guild *mGuild;
};
class PartyTab : public SocialTab, public gcn::ActionListener
{
public:
PartyTab(Party *party):
mParty(party)
{
setCaption(party->getName());
setTabColor(&Theme::getThemeColor(Theme::PARTY_SOCIAL_TAB));
mList = std::make_unique(party);
mScroll = std::make_unique(mList.get());
mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_AUTO);
}
void action(const gcn::ActionEvent &event) override
{
if (event.getId() == "do invite")
{
std::string name = mInviteDialog->getText();
if (!name.empty())
serverNotice(strprintf(_("Invited user %s to party."),
name.c_str()));
mInviteDialog = nullptr;
}
else if (event.getId() == "~do invite")
{
mInviteDialog = nullptr;
}
else if (event.getId() == "yes")
{
Net::getPartyHandler()->leave();
serverNotice(strprintf(_("Party %s quit requested."),
mParty->getName().c_str()));
mConfirmDialog = nullptr;
}
else if (event.getId() == "no")
{
mConfirmDialog = nullptr;
}
}
protected:
void invite() override
{
// TODO - Give feedback on whether the invite succeeded
mInviteDialog = new TextDialog(_("Member Invite to Party"),
strprintf(_("Who would you like to invite to party %s?"),
mParty->getName().c_str()),
socialWindow, true);
mInviteDialog->setActionEventId("do invite");
mInviteDialog->addActionListener(this);
}
void leave() override
{
mConfirmDialog = new ConfirmDialog(_("Leave Party?"),
strprintf(_("Are you sure you want to leave party %s?"),
mParty->getName().c_str()),
socialWindow);
mConfirmDialog->addActionListener(this);
}
private:
Party *mParty;
};
class PlayerList : public AvatarListModel
{
public:
void setPlayers(const std::vector &players)
{
delete_all(mPlayers);
mPlayers = players;
}
/**
* Returns the number of players in the list.
*/
int getNumberOfElements() override
{
return mPlayers.size();
}
Avatar *getAvatarAt(int index) override
{
return mPlayers[index];
}
private:
std::vector mPlayers;
};
class PlayerListTab : public SocialTab
{
public:
PlayerListTab()
{
mPlayerList = new PlayerList;
mList = std::make_unique(mPlayerList);
mScroll = std::make_unique(mList.get());
mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_AUTO);
}
~PlayerListTab()
{
delete mPlayerList;
}
void setPlayers(const std::vector &players)
{
mPlayerList->setPlayers(players);
}
protected:
void invite() override {}
void leave() override {}
private:
PlayerList *mPlayerList;
};
/*class BuddyTab : public SocialTab
{
// TODO?
};*/
class CreatePopup : public Popup, public LinkHandler
{
public:
CreatePopup():
Popup("SocialCreatePopup")
{
mBrowserBox = new BrowserBox;
mBrowserBox->setHighlightMode(BrowserBox::BACKGROUND);
mBrowserBox->setLinkHandler(this);
if (Net::getGuildHandler()->isSupported())
mBrowserBox->addRow(strprintf("@@guild|%s@@", _("Create Guild")));
mBrowserBox->addRow(strprintf("@@party|%s@@", _("Create Party")));
mBrowserBox->addRow("##3---");
mBrowserBox->addRow(strprintf("@@cancel|%s@@", _("Cancel")));
add(mBrowserBox);
setContentSize(mBrowserBox->getWidth(),
mBrowserBox->getHeight());
}
void handleLink(const std::string &link) override
{
if (link == "guild")
{
socialWindow->showGuildCreate();
}
else if (link == "party")
{
socialWindow->showPartyCreate();
}
setVisible(false);
}
void show(gcn::Widget *parent)
{
int x, y;
parent->getAbsolutePosition(x, y);
y += parent->getHeight();
setPosition(x, y);
setVisible(true);
requestMoveToTop();
}
private:
BrowserBox* mBrowserBox;
};
SocialWindow::SocialWindow() :
Window(_("Social"))
{
setWindowName("Social");
setVisible(false);
setSaveVisible(true);
setResizable(true);
setSaveVisible(true);
setCloseButton(true);
setMinWidth(120);
setMinHeight(55);
setDefaultSize(590, 200, 150, 124);
setupWindow->registerWindowForReset(this);
loadWindowState();
mCreateButton = new Button(_("Create"), "create", this);
mInviteButton = new Button(_("Invite"), "invite", this);
mLeaveButton = new Button(_("Leave"), "leave", this);
mTabs = new TabbedArea;
place(0, 0, mCreateButton);
place(1, 0, mInviteButton);
place(2, 0, mLeaveButton);
place(0, 1, mTabs, 4, 4);
widgetResized(nullptr);
mCreatePopup = new CreatePopup;
mPlayerListTab = new PlayerListTab;
mPlayerListTab->setCaption(strprintf(_("Online (%zu)"), 0ul));
mTabs->addTab(mPlayerListTab, mPlayerListTab->mScroll.get());
if (local_player->getParty())
{
addTab(local_player->getParty());
}
else
updateButtons();
}
SocialWindow::~SocialWindow()
{
// Cleanup invites
if (mGuildAcceptDialog)
{
mGuildAcceptDialog->close();
mGuildAcceptDialog->scheduleDelete();
mGuildAcceptDialog = nullptr;
mGuildInvited = 0;
}
if (mPartyAcceptDialog)
{
mPartyAcceptDialog->close();
mPartyAcceptDialog->scheduleDelete();
mPartyAcceptDialog = nullptr;
mPartyInviter.clear();
}
delete mCreatePopup;
delete mPlayerListTab;
}
bool SocialWindow::addTab(Guild *guild)
{
if (mGuilds.find(guild) != mGuilds.end())
return false;
auto *tab = new GuildTab(guild);
mGuilds[guild] = tab;
mTabs->addTab(tab, tab->mScroll.get());
updateButtons();
return true;
}
bool SocialWindow::removeTab(Guild *guild)
{
auto it = mGuilds.find(guild);
if (it == mGuilds.end())
return false;
mTabs->removeTab(it->second);
delete it->second;
mGuilds.erase(it);
updateButtons();
return true;
}
bool SocialWindow::addTab(Party *party)
{
if (mParties.find(party) != mParties.end())
return false;
auto *tab = new PartyTab(party);
mParties[party] = tab;
mTabs->addTab(tab, tab->mScroll.get());
updateButtons();
return true;
}
bool SocialWindow::removeTab(Party *party)
{
auto it = mParties.find(party);
if (it == mParties.end())
return false;
mTabs->removeTab(it->second);
delete it->second;
mParties.erase(it);
updateButtons();
return true;
}
void SocialWindow::action(const gcn::ActionEvent &event)
{
const std::string &eventId = event.getId();
if (event.getSource() == mPartyAcceptDialog)
{
// check if they accepted the invite
if (eventId == "yes")
{
serverNotice(strprintf(_("Accepted party invite from %s."),
mPartyInviter.c_str()));
Net::getPartyHandler()->inviteResponse(mPartyInviter, true);
}
else if (eventId == "no")
{
serverNotice(strprintf(_("Rejected party invite from %s."),
mPartyInviter.c_str()));
Net::getPartyHandler()->inviteResponse(mPartyInviter, false);
}
mPartyInviter.clear();
mPartyAcceptDialog = nullptr;
}
else if (event.getSource() == mGuildAcceptDialog)
{
// check if they accepted the invite
if (eventId == "yes")
{
serverNotice(_("Accepted guild invite"));
Net::getGuildHandler()->inviteResponse(mGuildInvited, true);
}
else if (eventId == "no")
{
serverNotice(_("Rejected guild invite."));
Net::getGuildHandler()->inviteResponse(mGuildInvited, false);
}
mGuildInvited = 0;
mGuildAcceptDialog = nullptr;
}
else if (event.getId() == "create")
{
if (Net::getGuildHandler()->isSupported())
mCreatePopup->show(mCreateButton);
else
showPartyCreate();
}
else if (event.getId() == "invite" && mTabs->getSelectedTabIndex() > -1)
{
static_cast(mTabs->getSelectedTab())->invite();
}
else if (event.getId() == "leave" && mTabs->getSelectedTabIndex() > -1)
{
static_cast(mTabs->getSelectedTab())->leave();
}
else if (event.getId() == "create guild")
{
std::string name = mGuildCreateDialog->getText();
if (name.size() > 16)
{
serverNotice(_("Creating guild failed, please choose a "
"shorter name."));
return;
}
if (!name.empty())
{
Net::getGuildHandler()->create(name);
serverNotice(strprintf(_("Creating guild called %s."),
name.c_str()));
}
mGuildCreateDialog = nullptr;
}
else if (event.getId() == "~create guild")
{
mGuildCreateDialog = nullptr;
}
else if (event.getId() == "create party")
{
std::string name = mPartyCreateDialog->getText();
if (name.size() > 16)
{
serverNotice(_("Creating party failed, please choose a "
"shorter name."));
return;
}
if (!name.empty())
{
Net::getPartyHandler()->create(name);
serverNotice(strprintf(_("Creating party called %s."),
name.c_str()));
}
mPartyCreateDialog = nullptr;
}
else if (event.getId() == "~create party")
{
mPartyCreateDialog = nullptr;
}
}
void SocialWindow::showGuildCreate()
{
mGuildCreateDialog = new TextDialog(_("Guild Name"),
_("Choose your guild's name."), this);
mGuildCreateDialog->setActionEventId("create guild");
mGuildCreateDialog->addActionListener(this);
}
void SocialWindow::showGuildInvite(const std::string &guildName,
const int guildId,
const std::string &inviterName)
{
// check there isnt already an invite showing
if (mGuildInvited != 0)
{
serverNotice(_("Received guild request, but one already exists."));
return;
}
std::string msg = strprintf(_("%s has invited you to join the guild %s."),
inviterName.c_str(), guildName.c_str());
serverNotice(msg);
// show invite
mGuildAcceptDialog = new ConfirmDialog(_("Accept Guild Invite"), msg, this);
mGuildAcceptDialog->addActionListener(this);
mGuildInvited = guildId;
}
void SocialWindow::showPartyInvite(const std::string &inviter,
const std::string &partyName)
{
// check there isnt already an invite showing
if (!mPartyInviter.empty())
{
serverNotice(_("Received party request, but one already exists."));
return;
}
std::string msg;
if (inviter.empty())
{
if (partyName.empty())
{
msg = _("You have been invited you to join a party.");
}
else
{
msg = strprintf(_("You have been invited to join the %s party."),
partyName.c_str());
}
}
else
{
if (partyName.empty())
{
msg = strprintf(_("%s has invited you to join their party."),
inviter.c_str());
}
else
{
msg = strprintf(_("%s has invited you to join the %s party."),
inviter.c_str(), partyName.c_str());
}
}
serverNotice(msg);
// show invite
mPartyAcceptDialog = new ConfirmDialog(_("Accept Party Invite"), msg, this);
mPartyAcceptDialog->addActionListener(this);
mPartyInviter = inviter;
}
void SocialWindow::showPartyCreate()
{
if (local_player->getParty())
{
new OkDialog(_("Create Party"),
_("Cannot create party. You are already in a party."),
true, this);
return;
}
mPartyCreateDialog = new TextDialog(_("Party Name"),
_("Choose your party's name."), this);
mPartyCreateDialog->setActionEventId("create party");
mPartyCreateDialog->addActionListener(this);
}
void SocialWindow::setPlayersOnline(const std::vector &players)
{
mPlayerListTab->setPlayers(players);
mPlayerListTab->setCaption(strprintf(_("Online (%zu)"), players.size()));
}
void SocialWindow::logic()
{
if (mOnlineListUpdateTimer.passed())
{
Net::getChatHandler()->requestOnlineList();
mOnlineListUpdateTimer.set(18000);
}
Window::logic();
}
void SocialWindow::updateButtons()
{
bool hasTabs = mTabs->getNumberOfTabs() > 0;
mInviteButton->setEnabled(hasTabs);
mLeaveButton->setEnabled(hasTabs);
}