stk-code_catmod/src/states_screens/online_user_search.cpp
2015-10-09 09:43:50 +11:00

275 lines
9.9 KiB
C++

// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2010-2015 Lucas Baudin, Joerg Henrichs
//
// 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 3
// of the License, or (at your option) 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, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "states_screens/online_user_search.hpp"
#include "audio/sfx_manager.hpp"
#include "config/player_manager.hpp"
#include "guiengine/modaldialog.hpp"
#include "online/profile_manager.hpp"
#include "states_screens/dialogs/user_info_dialog.hpp"
#include "states_screens/dialogs/message_dialog.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/translation.hpp"
#include "utils/string_utils.hpp"
using namespace Online;
#include <assert.h>
#include <iostream>
DEFINE_SCREEN_SINGLETON( OnlineUserSearch );
// ----------------------------------------------------------------------------
OnlineUserSearch::OnlineUserSearch() : Screen("online/user_search.stkgui")
{
m_search_request = NULL;
m_search_string = "";
m_last_search_string = "";
} // OnlineUserSearch
// ----------------------------------------------------------------------------
OnlineUserSearch::~OnlineUserSearch()
{
} // OnlineUserSearch
// ----------------------------------------------------------------------------
/** Callback when the xml file was loaded.
*/
void OnlineUserSearch::loadedFromFile()
{
m_back_widget = getWidget<GUIEngine::IconButtonWidget>("back");
assert(m_back_widget != NULL);
m_search_button_widget = getWidget<GUIEngine::ButtonWidget>("search_button");
assert(m_search_button_widget != NULL);
m_search_box_widget = getWidget<GUIEngine::TextBoxWidget>("search_box");
assert(m_search_box_widget != NULL);
m_user_list_widget = getWidget<GUIEngine::ListWidget>("user_list");
assert(m_user_list_widget != NULL);
} // loadedFromFile
// ----------------------------------------------------------------------------
/** Callback before widgets are added. Clears all widgets.
*/
void OnlineUserSearch::beforeAddingWidget()
{
m_user_list_widget->clearColumns();
m_user_list_widget->addColumn(_("Username"), 3);
}
// ----------------------------------------------------------------------------
/** Called when entering this menu (before widgets are added).
*/
void OnlineUserSearch::init()
{
Screen::init();
search();
m_search_box_widget->setText(m_search_string);
} // init
// ----------------------------------------------------------------------------
/** Callback before the screen is removed.
*/
void OnlineUserSearch::tearDown()
{
// The search request can be in one of three states:
// 1. It does not exist, nothing more to do.
// 2. It has been executed by the request manager, had its callback done
// and waits for this widget to collect the results. In this case, the
// requests state is 'isDone', and the memory of this object need to be
// freed here.
// 3. It is being executed by the request manager thread. In this case the
// request can not be freed (since the request manager might still
// write to it). In this case we set the flag that the request manager
// should manage the memory for the request, i.e. the request will be
// deleted once it is in the request manager's ready queue.
// Note that there is no race condition here: setting a request to be
// 'done', and checking if its memory need to be freed is done by the
// main thread (i.e. the same thread that executes this function ). So it
// is not possible that the thread stage changes to be 'isDone' while
// this function executes, or that the request is checked if it should
// be freed.
if (m_search_request)
{
// Check if the request is ready (but its result have not been
// received here ... otherwise it would have been deleted).
if (m_search_request->isDone())
{
delete m_search_request;
}
else
{
// This request is currently being handled by the request manager.
// We can set the memory management flag, since the separate
// request manager thread does not read or write this flag.
// The actual deletion of the request is done by the main
// thread, so there is no risk that the request is deleted
// between the next two calls!!
m_search_request->setManageMemory(true);
// Set cancel flag to speed up cancellation of this request
m_search_request->cancel();
}
} // if m_search_request
} // tearDown
// ----------------------------------------------------------------------------
/** Adds the results of the query to the ProfileManager cache.
* \param input The XML node with all user data.
*/
void OnlineUserSearch::parseResult(const XMLNode * input)
{
m_users.clear();
const XMLNode * users_xml = input->getNode("users");
// Try to reserve enough cache space for all found entries.
unsigned int n = ProfileManager::get()
->guaranteeCacheSize(users_xml->getNumNodes());
if (n >= users_xml->getNumNodes())
{
n = users_xml->getNumNodes();
}
else
{
Log::warn("OnlineSearch",
"Too many results found, only %d will be displayed.", n);
}
for (unsigned int i = 0; i < n; i++)
{
OnlineProfile * profile = new OnlineProfile(users_xml->getNode(i));
// The id must be pushed before adding it to the cache, since
// the cache might merge the new data with an existing entry
m_users.push_back(profile->getID());
ProfileManager::get()->addToCache(profile);
} // for i = 0 ... number of display users
} // parseResult
// ----------------------------------------------------------------------------
/** Takes the list of user ids from a query and shows it in the list gui.
*/
void OnlineUserSearch::showList()
{
m_user_list_widget->clear();
for (unsigned int i = 0; i < m_users.size(); i++)
{
std::vector<GUIEngine::ListWidget::ListCell> row;
OnlineProfile * profile = ProfileManager::get()->getProfileByID(m_users[i]);
// This could still happen if something pushed results out of the cache.
if (!profile)
{
Log::warn("OnlineSearch", "User %d not in cache anymore, ignored.", m_users[i]);
continue;
}
row.push_back(GUIEngine::ListWidget::ListCell(profile->getUserName(),-1,3));
m_user_list_widget->addItem("user", row);
}
} // showList
// ----------------------------------------------------------------------------
/** Called when a search is triggered. When it is a new search (and not just
* searching for the same string again), a request will be queued to
* receive the search results
*/
void OnlineUserSearch::search()
{
if (m_search_string != "" && m_last_search_string != m_search_string)
{
m_search_request = new XMLRequest();
PlayerManager::setUserDetails(m_search_request, "user-search");
m_search_request->addParameter("search-string", m_search_string);
m_search_request->queue();
m_user_list_widget->clear();
m_user_list_widget->addItem("spacer", L"");
m_user_list_widget->addItem("loading", StringUtils::loadingDots(_("Searching")));
m_back_widget->setActive(false);
m_search_box_widget->setActive(false);
m_search_button_widget->setActive(false);
}
} // search
// ----------------------------------------------------------------------------
/** Called when an event occurs (i.e. user clicks on something).
*/
void OnlineUserSearch::eventCallback(GUIEngine::Widget* widget,
const std::string& name,
const int player_id)
{
if (name == m_back_widget->m_properties[GUIEngine::PROP_ID])
{
StateManager::get()->escapePressed();
}
else if (name == m_user_list_widget->m_properties[GUIEngine::PROP_ID])
{
int selected_index = m_user_list_widget->getSelectionID();
if (selected_index != -1)
new UserInfoDialog(m_users[selected_index]);
}
else if (name == m_search_button_widget->m_properties[GUIEngine::PROP_ID])
{
m_last_search_string = m_search_string;
m_search_string = m_search_box_widget->getText().trim();
search();
}
} // eventCallback
// ----------------------------------------------------------------------------
/** Called every frame. It queries the search request for results and
* displays them if necessary.
*/
void OnlineUserSearch::onUpdate(float dt)
{
if(m_search_request != NULL)
{
if(m_search_request->isDone())
{
if(m_search_request->isSuccess())
{
parseResult(m_search_request->getXMLData());
showList();
}
else
{
SFXManager::get()->quickSound( "anvil" );
new MessageDialog(m_search_request->getInfo());
}
delete m_search_request;
m_search_request = NULL;
m_back_widget->setActive(true);
m_search_box_widget->setActive(true);
m_search_button_widget->setActive(true);
}
else
{
m_user_list_widget->renameItem("loading",
StringUtils::loadingDots(_("Searching")) );
}
}
} // onUpdate