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