The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
manager_impl.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2017 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project http://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 
16 
17 #include "game_events/handlers.hpp"
18 #include "formula/string_utils.hpp"
19 #include "log.hpp"
21 
22 #include <boost/algorithm/string.hpp>
23 
24 #include <iostream>
25 
26 static lg::log_domain log_engine("engine");
27 #define DBG_NG LOG_STREAM(debug, log_engine)
28 #define LOG_NG LOG_STREAM(info, log_engine)
29 #define WRN_NG LOG_STREAM(warn, log_engine)
30 
31 static lg::log_domain log_event_handler("event_handler");
32 #define DBG_EH LOG_STREAM(debug, log_event_handler)
33 
34 namespace game_events
35 {
37 {
38  if(lg::debug().dont_log("event_handler")) {
39  return;
40  }
41 
42  std::stringstream ss;
43 
44  for(const handler_ptr& h : active_) {
45  if(!h) {
46  continue;
47  }
48 
49  const config& cfg = h->get_config();
50  ss << "name=" << cfg["name"] << ", with id=" << cfg["id"] << "; ";
51  }
52 
53  DBG_EH << "active handlers are now " << ss.str() << "\n";
54 }
55 
56 /**
57  * Utility to standardize the event names used in by_name_.
58  * This means stripping leading and trailing spaces, and converting internal
59  * spaces to underscores.
60  */
62 {
63  std::string retval = name;
64 
65  // Trim leading and trailing spaces.
66  boost::trim(retval);
67 
68  // Replace internal spaces with underscores.
69  boost::replace_all(retval, " ", "_");
70 
71  return retval;
72 }
73 
74 /**
75  * Read-only access to the handlers with fixed event names, by event name.
76  */
78 {
79  // Empty list for the "not found" case.
80  static handler_list empty_list;
81 
82  // Look for the name in the name map.
83  auto find_it = by_name_.find(standardize_name(name));
84  return find_it == by_name_.end() ? empty_list : find_it->second;
85 }
86 
87 /**
88  * Adds an event handler.
89  * An event with a nonempty ID will not be added if an event with that
90  * ID already exists.
91  */
92 void event_handlers::add_event_handler(const config& cfg, bool is_menu_item)
93 {
94  std::string name = cfg["name"];
95  std::string id = cfg["id"];
96 
97  if(!id.empty()) {
98  // Ignore this handler if there is already one with this ID.
99  auto find_it = id_map_.find(id);
100  if(find_it != id_map_.end() && !find_it->second.expired()) {
101  DBG_EH << "ignoring event handler for name='" << name << "' with id '" << id << "'\n";
102  return;
103  }
104  }
105 
106  // Make a copy of the event cfg here in order to do some standardization on the
107  // name field. Will be moved into the handler.
108  config event_cfg = cfg;
109 
110  // Split the name field...
111  std::vector<std::string> standardized_names = utils::split(cfg["name"]);
112 
113  // ...and standardize each one individually. This ensures they're all valid for by-name lookup.
114  for(std::string& single_name : standardized_names) {
115  single_name = standardize_name(single_name);
116  }
117 
118  // Write the new name back to the config.
119  name = utils::join(standardized_names);
120  event_cfg["name"] = name;
121 
122  // Create a new handler.
123  // Do note active_ holds the main shared_ptr, and the other three containers
124  // construct weak_ptrs from the shared one.
125  DBG_EH << "inserting event handler for name=" << name << " with id=" << id << "\n";
126  active_.emplace_back(new event_handler(std::move(event_cfg), is_menu_item));
127 
128  //
129  // !! event_cfg is invalid past this point! DO NOT USE!
130  //
131 
132  // File by name.
134  dynamic_.emplace_back(active_.back());
135  } else {
136  for(const std::string& single_name : standardized_names) {
137  by_name_[single_name].emplace_back(active_.back());
138  }
139  }
140 
141  // File by ID.
142  if(!id.empty()) {
143  id_map_[id] = active_.back();
144  }
145 
146  log_handlers();
147 }
148 
149 /**
150  * Removes an event handler, identified by its ID.
151  * Events with empty IDs cannot be removed.
152  */
154 {
155  if(id.empty()) {
156  return;
157  }
158 
159  DBG_EH << "removing event handler with id " << id << "\n";
160 
161  // Find the existing handler with this ID.
162  auto find_it = id_map_.find(id);
163  if(find_it != id_map_.end()) {
164  handler_ptr handler = find_it->second.lock();
165 
166  if(handler && !handler->disabled()) {
167  handler->disable();
168  }
169 
170  // Do this even if the lock failed.
171  id_map_.erase(find_it);
172 
173  // Remove handler from other lists if we got a lock. If we didn't, the handler
174  // was already from the main list previously, so any other weak_ptrs to it in
175  // the by-name or with-vars list should already have been dropped. If for some
176  // reason they haven't, no problem. They don't do anything and will be dropped
177  // next cleanup.
178  if(handler) {
179  clean_up_expired_handlers(handler->get_config()["name"]);
180  }
181  }
182 
183  log_handlers();
184 }
185 
187 {
188  // First, remove all disabled handlers from the main list.
189  auto to_remove = std::remove_if(active_.begin(), active_.end(),
190  [](handler_ptr p) { return p->disabled(); }
191  );
192 
193  active_.erase(to_remove, active_.end());
194 
195  // Then remove any now-unlockable weak_ptrs from the by-name list.
196  // Might be more than one so we split.
197  for(const std::string& name : utils::split(event_name)) {
198  get(name).remove_if(
199  [](weak_handler_ptr ptr) { return ptr.expired(); }
200  );
201  }
202 
203  // And finally remove any now-unlockable weak_ptrs from the with-variables name list.
204  dynamic_.remove_if(
205  [](weak_handler_ptr ptr) { return ptr.expired(); }
206  );
207 }
208 
210 {
211  auto find_it = id_map_.find(id);
212  if(find_it != id_map_.end() && !find_it->second.expired()) {
213  return find_it->second.lock();
214  }
215 
216  return nullptr;
217 }
218 
219 } // end namespace game_events
std::vector< char_t > string
handler_vec_t active_
Active event handlers.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
static std::string standardize_name(const std::string &name)
Utility to standardize the event names used in by_name_.
handler_list & get(const std::string &name)
Access to the handlers with fixed event names, by event name.
void clean_up_expired_handlers(const std::string &event_name)
Removes all expired event handlers and any weak_ptrs to them.
#define h
id_map_t id_map_
Allows quick locating of handlers by id.
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
void remove_event_handler(const std::string &id)
Removes an event handler, identified by its ID.
handler_list dynamic_
Active event handlers with variables in their event names.
static lg::log_domain log_engine("engine")
std::weak_ptr< event_handler > weak_handler_ptr
Definition: fwd.hpp:25
logger & debug()
Definition: log.cpp:97
Domain specific events.
Definition: action_wml.cpp:88
void add_event_handler(const config &cfg, bool is_menu_item=false)
Adds an event handler.
mock_party p
map_t by_name_
Active event handlers with fixed event names, organized by event name.
bool might_contain_variables(const std::string &str)
Determines if a string might contain variables to interpolate.
std::list< weak_handler_ptr > handler_list
Definition: fwd.hpp:26
Define the handlers for the game's events mechanism.
Standard logging facilities (interface).
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
static lg::log_domain log_event_handler("event_handler")
std::shared_ptr< event_handler > handler_ptr
Definition: fwd.hpp:24
const handler_ptr get_event_handler_by_id(const std::string &id)
Gets an event handler, identified by its ID.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
#define DBG_EH