The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
file_menu.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[email protected]>
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 
15 #include "global.hpp"
16 
17 #define GETTEXT_DOMAIN "wesnoth-lib"
18 
19 #include "filesystem.hpp"
20 #include "marked-up_text.hpp"
21 #include "wml_separators.hpp"
22 #include "widgets/file_menu.hpp"
23 
24 
25 namespace {
26  std::vector<std::string> empty_string_vector;
27 
28 
29  std::string uniform_path(const std::string& path)
30  {
31 #ifdef _WIN32
33  std::replace(res.begin(), res.end(), '/', '\\');
34  return res;
35 #else
36  return path;
37 #endif
38  }
39 
40 }
41 
42 namespace gui {
43 
44 static const std::string dir_picture("misc/folder-icon.png");
45 static const std::string path_up("..");
46 #ifdef _WIN32
47 const char file_menu::path_delim('\\');
48 #else
49 const char file_menu::path_delim('/');
50 #endif
51 
53  : menu(disp, empty_string_vector, false),
54  current_dir_(uniform_path(get_path(start_file))),
55  chosen_file_(start_file), last_selection_(-1),
56  type_a_head_(-1)
57 {
58  // If the start file is not a file or directory, use the root.
63  }
64  // FIXME: quick hack
65  // on a high-res screen the initial max_items_onscreen is based
66  // on .66 of y dimension, eg. 17 menu items, exceeding the
67  // starting box which can only take 13 or so: force it to be smaller
68 // set_measurements(400, 384);
70 }
71 
73  std::vector<std::string> to_show;
74  if (!is_root(current_dir_)) {
75  to_show.push_back(path_up);
76  }
78  for (it = dirs_in_current_dir_.begin(); it != dirs_in_current_dir_.end(); ++it) {
79  // Add an image to show that these are directories.
80  std::stringstream ss;
82  to_show.push_back(ss.str());
83  }
84  for (it = files_in_current_dir_.begin(); it != files_in_current_dir_.end(); ++it) {
85  const std::string display_string = COLUMN_SEPARATOR + std::string(1, font::NULL_MARKUP) + *it;
86  to_show.push_back(display_string);
87  }
88  const int menu_font_size = font::SIZE_NORMAL; // Known from menu.cpp.
89  for (it = to_show.begin(); it != to_show.end(); ++it) {
90  // Make sure that all lines fit.
91  // Guess the width of the scrollbar to be 30 since it is not accessible from here.
92  // -25 to compensate for the picture column.
93  if (get_max_width() != -1) {
94  while(font::line_width(*it, menu_font_size) > width() - 30 - 25) {
95  //we cannot decrease its size if its empty.
96  assert(!(*it).empty());
97  (*it).resize((*it).size() - 1);
98  }
99  }
100  }
101  set_items(to_show);
102 }
103 
105  const int ret = filesystem::delete_file(chosen_file_);
106  if (ret == -1) {
107  // gui2::show_transient_message(disp_.video(), "", _("Deletion of the file failed."));
108  }
109  else {
110  last_selection_ = -1;
113  }
114  return ret;
115 }
116 
117 bool file_menu::make_directory(const std::string& subdir_name) {
118  bool ret = ::filesystem::make_directory(add_path(current_dir_, subdir_name));
119  if (ret == false) {
120  // gui2::show_transient_message(disp_.video(), "", _("Creation of the directory failed."));
121  }
122  else {
123  last_selection_ = -1;
126  }
127  return ret;
128 }
129 
130 void file_menu::handle_event(const SDL_Event& event) {
131  menu::handle_event(event);
132 
133  if(selection() != last_selection_
134  && !type_a_head()) {
135  type_a_head_ = -1;
138  }
139 }
140 
141 void file_menu::entry_selected(const unsigned entry) {
142  const int entry_index = entry - (is_root(current_dir_) ? 0 : 1);
143  if (entry_index >= 0) {
145  if(static_cast<unsigned>(entry_index) < dirs_in_current_dir_.size()) {
146  const int dir_index = entry_index;
147  selected = dirs_in_current_dir_[dir_index];
148  }
149  else {
150  const int file_index = entry_index - dirs_in_current_dir_.size();
151  if(file_index >= 0 && size_t(file_index) < files_in_current_dir_.size()) {
152  selected = files_in_current_dir_[file_index];
153  } else {
154  return;
155  }
156  }
157  chosen_file_ = add_path(current_dir_, selected);
158  } else {
160  }
161 }
162 
163 bool file_menu::is_directory(const std::string& fname) const {
164  if(fname == path_up)
165  return true;
167 }
168 
170  if(path == path_up)
171  {
172  // Parent dir wanted.
173  if (!is_root(current_dir_)) {
175  last_selection_ = -1;
178  }
179  else {
180  return;
181  }
182 
183  } else {
184  current_dir_ = uniform_path(path);
186  last_selection_ = -1;
188  }
189 }
190 
192  return chosen_file_;
193 }
194 
195 
196 std::string file_menu::get_path(const std::string& file_or_dir) const {
197  std::string res_path = file_or_dir;
198  if (!::filesystem::is_directory(file_or_dir)) {
199  size_t index = file_or_dir.find_last_of(path_delim);
200  if (index != std::string::npos) {
201  res_path = file_or_dir.substr(0, index);
202  }
203  }
204  return res_path;
205 }
206 
208  std::string curr_path = get_path(path);
209  for (unsigned i = 0; i < levels; i++) {
210  if (is_root(curr_path)) {
211  break;
212  }
213  curr_path = strip_last_delim(curr_path);
214  size_t index = curr_path.find_last_of(path_delim);
215  if (index != std::string::npos) {
216  curr_path = curr_path.substr(0, index);
217  }
218  else {
219  break;
220  }
221  }
222  if (curr_path.empty()) {
223  // The root was reached, represent this as one delimiter only.
224  curr_path = path_delim;
225  }
226 #ifdef _WIN32
227  if (curr_path.size() == 2 && curr_path[1] == ':') curr_path += path_delim;
228 #endif
229  return curr_path;
230 }
231 
233  std::string res_string = path;
234  if (path[path.size() - 1] == path_delim) {
235  res_string = path.substr(0, path.size() - 1);
236  }
237  return res_string;
238 }
239 
240 bool file_menu::is_root(const std::string& path) const {
241  return path.empty() || (path.size() == 1 && path[0] == path_delim);
242 }
243 
245 {
246  std::string joined_path = strip_last_delim(path);
247  if (!to_add.empty()) {
248  if (to_add == path_up) {
249  return get_path_up(path);
250  }
251 #ifdef _WIN32
252  else if (to_add.size() > 1 && to_add[1] == ':') {
253  joined_path = to_add;
254  }
255 #else
256  else if (to_add[0] == path_delim) {
257  joined_path = to_add;
258  }
259 #endif
260  else {
261  joined_path += "/" + to_add;
262  }
263  }
264  return joined_path;
265 }
266 
267 struct match_begin {
268  match_begin(const std::string& begin) : begin_(begin)
269  {}
270 
271  bool operator()(const std::string& o) const
272  {
273  return o.compare(0, begin_.size(), begin_) == 0;
274  }
275 
276  private:
278 };
279 
281 {
282  return selection() == type_a_head_;
283 }
284 
286 {
287  if (type_a_head_ >= 0)
288  {
291  }
292  type_a_head_ = -1;
293 }
294 
295 void file_menu::select_file(const std::string& begin_of_filename)
296 {
297  size_t additional_index = is_root(current_dir_) ? 0 : 1;
299  it = std::find_if(dirs_in_current_dir_.begin(), dirs_in_current_dir_.end(), match_begin(begin_of_filename));
300  if (it != dirs_in_current_dir_.end())
301  {
302  type_a_head_ = additional_index + it - dirs_in_current_dir_.begin();
304  return;
305  }
306  additional_index += dirs_in_current_dir_.size();
307 
308  it = std::find_if(files_in_current_dir_.begin(), files_in_current_dir_.end(), match_begin(begin_of_filename));
309  if (it != files_in_current_dir_.end())
310  {
311  type_a_head_ = it - files_in_current_dir_.begin() + additional_index;
313  return;
314  }
315 }
316 
318  files_in_current_dir_.clear();
319  dirs_in_current_dir_.clear();
323 }
324 
325 }
static const char path_delim
Definition: file_menu.hpp:28
bool delete_file(const std::string &filename)
static const std::string dir_picture("misc/folder-icon.png")
bool make_directory(const std::string &subdir_name)
Definition: file_menu.cpp:117
const char IMAGE
void handle_event(const SDL_Event &event)
Definition: file_menu.cpp:130
Definition: video.hpp:58
std::vector< std::string > dirs_in_current_dir_
Definition: file_menu.hpp:94
General purpose widgets.
std::vector< std::string > empty_string_vector
Definition: help_impl.cpp:75
file_menu(CVideo &disp, std::string start_file="")
Initialize the file menu.
Definition: file_menu.cpp:52
match_begin(const std::string &begin)
Definition: file_menu.cpp:268
static const std::string path_up("..")
virtual void handle_event(const SDL_Event &event)
Definition: menu.cpp:654
void entry_selected(const unsigned entry)
Set the textbox to reflect the selected file.
Definition: file_menu.cpp:141
std::vector< std::pair< const std::string *, const stats * > > levels
Stats (and name) for each scenario. The pointers are never nullptr.
Definition: statistics.hpp:115
const int SIZE_NORMAL
Definition: font.hpp:58
GLsizei const char ** path
Definition: glew.h:4654
std::string strip_last_delim(const std::string &path) const
Return the string with the last path delimiter removed, if one was there.
Definition: file_menu.cpp:232
void display_current_files()
Show the files in the current directory.
Definition: file_menu.cpp:72
int get_max_width()
Definition: menu.hpp:203
bool is_directory(const std::string &fname) const
Definition: file_menu.cpp:163
std::string selected
Definition: game_config.cpp:84
std::string get_path_up(const std::string &path, const unsigned levels=1) const
Return the path that is the specified number of levels up from the path.
Definition: file_menu.cpp:207
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
const std::string & begin_
Definition: file_menu.cpp:277
void reset_type_a_head()
Definition: file_menu.cpp:285
std::string get_choice() const
Return the chosen file.
Definition: file_menu.cpp:191
bool is_root(const std::string &path) const
Return true if the path is the root of the filesystem.
Definition: file_menu.cpp:240
virtual void set_items(const std::vector< std::string > &items, bool strip_spaces=true, bool keep_viewport=false)
Set new items to show and redraw/recalculate everything.
Definition: menu.cpp:446
void move_selection(size_t id)
Definition: menu.cpp:567
GLuint res
Definition: glew.h:9258
const char NULL_MARKUP
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs=nullptr, file_name_option mode=FILE_NAME_ONLY, file_filter_option filter=NO_FILTER, file_reorder_option reorder=DONT_REORDER, file_tree_checksum *checksum=nullptr)
Populates 'files' with all the files and 'dirs' with all the directories in dir.
GLuint index
Definition: glew.h:1782
void select_file(const std::string &begin_of_filename)
Selects file (type-a-head search)
Definition: file_menu.cpp:295
bool make_directory(const std::string &dirname)
std::string chosen_file_
Definition: file_menu.hpp:93
size_t i
Definition: function.cpp:1057
std::string current_dir_
Definition: file_menu.hpp:92
Declarations for File-IO.
std::string get_path(const std::string &file_or_dir) const
If file_or_dir is a file, return the directory the file is in, if it is a directory, return the directory name.
Definition: file_menu.cpp:196
void update_file_lists()
Updated the locally maintained lists of files and directories in the current directory.
Definition: file_menu.cpp:317
std::string replace(std::string str, const std::string &src, const std::string &dst)
Replace all instances of src in str with dst.
std::string add_path(const std::string &path, const std::string &to_add) const
Return path with to_add added, using a path delimiter between them.
Definition: file_menu.cpp:244
char const COLUMN_SEPARATOR
cl_event event
Definition: glew.h:3070
bool type_a_head() const
Definition: file_menu.cpp:280
int delete_chosen_file()
Definition: file_menu.cpp:104
bool operator()(const std::string &o) const
Definition: file_menu.cpp:271
void change_directory(const std::string &path)
Definition: file_menu.cpp:169
int width() const
Definition: widget.cpp:134
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
int line_width(const std::string &line, int font_size, int style)
Determine the width of a line of text given a certain font size.
Definition: font.cpp:969
std::vector< std::string > files_in_current_dir_
Definition: file_menu.hpp:94
int selection() const
Definition: menu.cpp:369