273 lines
9.9 KiB
C++
273 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>
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
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
|