The Battle for Wesnoth  1.15.12+dev
mp_connect.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
19 #include "gettext.hpp"
20 #include "preferences/game.hpp"
21 #include "gui/auxiliary/field.hpp"
24 #include "gui/widgets/button.hpp"
25 #include "gui/widgets/listbox.hpp"
26 #include "gui/widgets/settings.hpp"
27 
28 #include "log.hpp"
29 
30 #include <functional>
31 
32 #include <boost/algorithm/string/trim.hpp>
33 
34 static lg::log_domain log_mpconnect{"gui/dialogs/mp_connect"};
35 #define ERR_DLG LOG_STREAM(err, log_mpconnect)
36 #define WRN_DLG LOG_STREAM(warn, log_mpconnect)
37 #define LOG_DLG LOG_STREAM(info, log_mpconnect)
38 #define DBG_DLG LOG_STREAM(debug, log_mpconnect)
39 
40 namespace gui2
41 {
42 
43 namespace
44 {
45 
46 // NOTE: See mp_connect::select_first_match() below
47 #if 0
48 void clear_listbox_selection(listbox& listbox)
49 {
50  const auto selection = listbox.get_selected_row();
51  if(selection >= 0) {
52  listbox.select_row(selection, false);
53  }
54 }
55 #endif
56 
57 }
58 
59 namespace dialogs
60 {
61 
62 REGISTER_DIALOG(mp_connect)
63 
65  : host_name_(register_text("host_name",
66  true,
69  true))
70  , builtin_servers_(preferences::builtin_servers_list())
71  , user_servers_(preferences::user_servers_list())
72 {
73  set_restore(true);
74 }
75 
76 std::array<mp_connect::server_list*, 2> mp_connect::server_lists()
77 {
78  return {{ &builtin_servers_, &user_servers_ }};
79 }
80 
82 {
83  text_box& hostname_box = find_widget<text_box>(&win, "host_name", false);
84  listbox& server_list = find_widget<listbox>(&win, "server_list", false);
85  button& button_add = find_widget<button>(&win, "server_add", false);
86  button& button_del = find_widget<button>(&win, "server_delete", false);
87 
88  for(const auto* servers : server_lists()) {
89  for(const auto& server : *servers) {
90  insert_into_server_listbox(server_list, server);
91  }
92  }
93 
95 
96  connect_signal_notify_modified(hostname_box, std::bind(&mp_connect::on_address_change, this));
97  connect_signal_notify_modified(server_list, std::bind(&mp_connect::on_server_select, this));
98  connect_signal_mouse_left_click(button_add, std::bind(&mp_connect::on_server_add, this));
100 }
101 
103 {
104  const std::map<std::string, string_map>& entry{
105  { "name", string_map{{"label", srv.name}} },
106  { "address", string_map{{"label", srv.address}} },
107  };
108 
109  listbox.add_row(entry, pos);
110 }
111 
113 {
114  window* window = get_window();
115 
116  text_box& hostname_box = find_widget<text_box>(window, "host_name", false);
117  listbox& server_list = find_widget<listbox>(window, "server_list", false);
118  button& button_add = find_widget<button>(window, "server_add", false);
119  button& button_del = find_widget<button>(window, "server_delete", false);
120 
121  const auto& address = boost::trim_copy(hostname_box.get_value());
122 
123  std::size_t row = 0;
124 
125  for(const auto* servers : server_lists()) {
126  for(const auto& server : *servers) {
127  if(server.address == address) {
128  server_list.select_row(row);
129  // Can't Add what's already there or Delete built-in servers
130  button_add.set_active(false);
131  button_del.set_active(servers == &user_servers_);
132  return;
133  }
134 
135  ++row;
136  }
137  }
138 
139  // NOTE: Do not use this in production. It requires the listbox to be
140  // defined with has_minimum=false in WML, and makes some UI interactions
141  // awkward. In particular it means we would need to keep track of where
142  // the selection was last at every time we clear the selection so that
143  // the Add button can add under it instead of appending to the very end
144  // of the list (currently it just bails out if there's no selection).
145 #if 0
146  // The user wrote a brand new hostname in so there's no matches, clear the
147  // selection accordingly
148  clear_listbox_selection(server_list);
149  button_del.set_active(false);
150 #endif
151  button_add.set_active(!address.empty());
152 }
153 
155 {
156  // Select the first matching list entry or clear the current selection
158 }
159 
161 {
162  window* window = get_window();
163 
164  text_box& hostname_box = find_widget<text_box>(window, "host_name", false);
165  listbox& server_list = find_widget<listbox>(window, "server_list", false);
166 
167  const auto& address = boost::trim_copy(hostname_box.get_value());
168  const auto& selection = current_selection();
169 
170  if(address.empty() || !selection.valid()) {
171  // We're not supposed to be here
172  return;
173  }
174 
175  // We insert under the selection. If a built-in server is selected or the
176  // user-defined list is empty, we insert at the start of the user-defined
177  // list instead.
178 
179  const std::size_t mem_pos = selection.user_defined() && !user_servers_.empty()
180  ? 1 + selection.relative_index() : 0;
181  const unsigned int ui_pos = selection.user_defined() ? 1 + selection.row() : builtin_servers_.size();
182 
183  std::string name;
184 
185  if(!gui2::dialogs::edit_text::execute(_("Add Server"), _("Name:"), name, true) || name.empty()) {
186  return;
187  }
188 
190  info.name = name;
191  info.address = address;
192 
193  user_servers_.insert(user_servers_.begin() + mem_pos, info);
195 
196  insert_into_server_listbox(server_list, info, ui_pos);
198 }
199 
201 {
202  window* window = get_window();
203 
204  listbox& server_list = find_widget<listbox>(window, "server_list", false);
205 
206  auto selection = current_selection();
207 
208  if(!selection.valid() || !selection.user_defined()) {
209  // We're not supposed to be here
210  return;
211  }
212 
213  user_servers_.erase(user_servers_.begin() + selection.relative_index());
215 
216  server_list.remove_row(selection.row());
218 }
219 
221 {
222  window* window = get_window();
223 
224  text_box& hostname_box = find_widget<text_box>(window, "host_name", false);
225  button& button_add = find_widget<button>(window, "server_add", false);
226  button& button_del = find_widget<button>(window, "server_delete", false);
227 
228  auto selection = current_selection();
229 
230  if(!selection.valid()) {
231  // The user cleared the selection. We can't delete what isn't selected
232  // and the Add button's status was already set to a value that makes
233  // sense by another signal handler, so just disable Delete.
234  button_del.set_active(false);
235  return;
236  }
237 
238  hostname_box.set_value(selection.get().address);
239 
240  // Can't Add what's already there
241  button_add.set_active(false);
242  // Can only Delete user-defined servers
243  button_del.set_active(selection.user_defined());
244 }
245 
247 {
248  listbox& server_list = find_widget<listbox>(get_window(), "server_list", false);
249  return { this, server_list.get_selected_row() };
250 }
251 
253 {
254  must_be_valid();
255  return parent_list().at(relative_index());
256 }
257 
259 {
260  must_be_valid();
261  return unsigned(row_);
262 }
263 
265 {
266  must_be_valid();
267  return user_defined() ? row() - owner_->builtin_servers_.size() : row();
268 }
269 
271 {
272  must_be_valid();
273  return user_defined() ? owner_->user_servers_ : owner_->builtin_servers_;
274 }
275 
276 } // namespace dialogs
277 } // namespace gui2
server_list & parent_list() const
Definition: mp_connect.cpp:270
logger & info()
Definition: log.cpp:88
std::string get_value() const
std::string network_host()
Definition: game.cpp:395
window * get_window() const
Returns a pointer to the dialog&#39;s window.
void set_network_host(const std::string &host)
Definition: game.cpp:405
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:276
Implements some helper classes to ease adding fields to a dialog and hide the synchronization needed...
static std::string _(const char *str)
Definition: gettext.hpp:92
std::array< server_list *, 2 > server_lists()
Definition: mp_connect.cpp:76
std::string address
may include &#39;:&#39; followed by port number
Definition: game_config.hpp:76
Class for a single line text area.
Definition: text_box.hpp:140
Generic file dialog.
Definition: field-fwd.hpp:22
The listbox class.
Definition: listbox.hpp:42
const std::vector< game_config::server_info > & builtin_servers_list()
Definition: game.cpp:364
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification_function &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:186
This file contains the settings handling of the widget library.
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:171
This shows the dialog to the MP server to connect to.
Definition: mp_connect.hpp:41
void set_user_servers_list(const std::vector< game_config::server_info > &value)
Definition: game.cpp:383
Modify, read and display user preferences.
Various uncategorised dialogs.
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
Definition: mp_connect.cpp:81
std::map< std::string, t_string > string_map
Definition: widget.hpp:26
grid & add_row(const string_map &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:67
std::vector< server_info > server_list
Definition: mp_connect.hpp:67
virtual void set_value(const std::string &text)
The set_value is virtual for the password_box class.
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: button.cpp:62
Simple push button.
Definition: button.hpp:35
Standard logging facilities (interface).
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:87
void insert_into_server_listbox(listbox &listbox, const server_info &srv, int pos=-1)
Definition: mp_connect.cpp:102
std::vector< game_config::server_info > user_servers_list()
Definition: game.cpp:370
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:64
static lg::log_domain log_mpconnect
Definition: mp_connect.cpp:34