The Battle for Wesnoth  1.15.7+dev
file_dialog.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011, 2018 by Iris Morelle <shadowm2006@gmail.com>
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 "cursor.hpp"
20 #include "desktop/paths.hpp"
21 #include "filesystem.hpp"
22 #include "formula/string_utils.hpp"
25 #include "gui/dialogs/message.hpp"
27 #include "gui/widgets/button.hpp"
28 #include "gui/widgets/listbox.hpp"
29 #include "gui/widgets/settings.hpp"
30 #include "gui/widgets/text_box.hpp"
32 #include "gui/widgets/window.hpp"
33 #include "gettext.hpp"
34 #include "log.hpp"
36 
37 #include <functional>
38 
39 static lg::log_domain log_filedlg{"gui/dialogs/file_dialog"};
40 #define ERR_FILEDLG LOG_STREAM(err, log_filedlg)
41 #define WRN_FILEDLG LOG_STREAM(warn, log_filedlg)
42 #define LOG_FILEDLG LOG_STREAM(info, log_filedlg)
43 #define DBG_FILEDLG LOG_STREAM(debug, log_filedlg)
44 
45 namespace fs = filesystem;
46 
47 namespace
48 {
49 const std::string icon_dir = "misc/folder-icon.png";
50 // Empty icons with the same size as the above to force the icon column to have a
51 // specific size even when there are no folders in the list.
52 const std::string icon_file = icon_dir + "~O(0)";
53 const std::string icon_parent = icon_dir + "~O(0)";
54 // NOTE: Does not need to be the same as PARENT_DIR! Use PARENT_DIR to build
55 // relative paths for non-presentational purposes instead.
56 const std::string label_parent = "..";
57 
58 const std::string CURRENT_DIR = ".";
59 const std::string PARENT_DIR = "..";
60 
61 const int FILE_DIALOG_ITEM_RETVAL = 9001;
62 const int FILE_DIALOG_MAX_ENTRY_LENGTH = 42;
63 
64 inline std::string concat_path(const std::string& a, const std::string& b)
65 {
66  //
67  // As of Boost 1.61, normalize_path() displays unusual behavior when passing
68  // it paths with extra path separators (e.g. //opt becomes
69  // //opt/home/shadowm/src/wesnoth, where the extraneous sequence is probably
70  // the current working dir), so avoid leaving those around.
71  //
72  // TODO: Maybe handle this corner case in filesystem::normalize_path()
73  // instead, really.
74  //
75  if((a.empty() || !fs::is_path_sep(a.back())) && (b.empty() || !fs::is_path_sep(b.front()))) {
76  return a + fs::path_separator() + b;
77  } else {
78  return a + b;
79  }
80 }
81 
82 inline std::string filesystem_root()
83 {
84  // TODO: Multiple drives support (may require cooperation from the caller).
85  return std::string(1, fs::path_separator());
86 }
87 
88 inline void isort_dir_entries(std::vector<std::string>& entries)
89 {
90  // Yes, this uses Wesnoth's locale and not the filesystem/OS locale. Yes, this
91  // isn't ideal. No, we don't really need to worry about it. It's just a
92  // cosmetic procedure anyway.
93  std::sort(entries.begin(), entries.end(),
94  [](const std::string& a, const std::string& b) { return translation::icompare(a, b) < 0; });
95 }
96 
97 } // unnamed namespace
98 
99 namespace gui2
100 {
101 namespace dialogs
102 {
103 
104 REGISTER_DIALOG(file_dialog)
105 
107  : title_(_("Find File"))
108  , msg_()
109  , ok_label_()
110  , extension_()
111  , current_entry_()
112  , current_dir_()
113  , read_only_(false)
114  , save_mode_(false)
115  , dir_files_()
116  , dir_subdirs_()
117  , bookmark_paths_()
118  , current_bookmark_()
119  , user_bookmarks_begin_()
120 {
121  set_restore(true);
122 }
123 
125 {
126  const std::string& dir_norm = fs::normalize_path(current_dir_, true);
127 
128  if(current_entry_.empty() || current_entry_ == CURRENT_DIR) {
129  return dir_norm;
130  } else if(current_entry_ == PARENT_DIR) {
131  return fs::directory_name(dir_norm);
132  }
133 
134  return concat_path(dir_norm, current_entry_);
135 }
136 
138 {
139  if(value.empty()) {
140  current_dir_ = filesystem_root();
141  }
142 
143  const std::string& norm = fs::normalize_path(value, true);
144 
145  if(fs::is_directory(norm)) {
146  current_dir_ = norm;
147  } else {
149  if(current_dir_.empty()) {
150  current_dir_ = filesystem_root();
151  }
152  // The file may or may not exist. We'll find out eventually when setting up
153  // the dialog.
155  }
156 
157  return *this;
158 }
159 
161 {
162  current_entry_ = value;
163 
164  return *this;
165 }
166 
168 {
169  styled_widget& title = find_widget<styled_widget>(&window, "title", false);
170  styled_widget& message = find_widget<styled_widget>(&window, "message", false);
171  styled_widget& ok = find_widget<styled_widget>(&window, "ok", false);
172 
173  title.set_label(title_);
174 
175  if(msg_.empty()) {
176  message.set_visible(gui2::widget::visibility::invisible);
177  } else {
178  message.set_label(msg_);
179  message.set_use_markup(true);
180  }
181 
182  if(ok_label_.empty()) {
183  ok.set_label(save_mode_ ? _("Save") : _("Open"));
184  } else {
185  ok.set_label(ok_label_);
186  }
187 
188  listbox& bookmarks_bar = find_widget<listbox>(&window, "bookmarks", false);
189 
190  find_widget<styled_widget>(&window, "current_dir", false).set_text_ellipse_mode(PANGO_ELLIPSIZE_START);
191 
192  //
193  // Push hard-coded bookmarks.
194  //
195 
196  std::vector<desktop::path_info> bookmarks = desktop::game_paths();
197  const auto& sys_paths = desktop::system_paths();
198  bookmarks.insert(bookmarks.end(), sys_paths.begin(), sys_paths.end());
199 
200  bookmark_paths_.clear();
202 
203  std::map<std::string, string_map> data;
204 
205  for(const auto& pinfo : bookmarks) {
206  bookmark_paths_.push_back(pinfo.path);
207  data["bookmark"]["label"] = pinfo.display_name();
208  bookmarks_bar.add_row(data);
209  }
210 
211  //
212  // Push user-defined bookmarks.
213  //
214 
215  const std::vector<desktop::bookmark_info>& user_bookmarks = desktop::user_bookmarks();
216 
217  if(!user_bookmarks.empty()) {
219  }
220 
221  for(const auto& bookmark : user_bookmarks) {
222  bookmark_paths_.push_back(bookmark.path);
223  data["bookmark"]["label"] = bookmark.label;
224  bookmarks_bar.add_row(data);
225  }
226 
228 
229  listbox& filelist = find_widget<listbox>(&window, "filelist", false);
230 
232  std::bind(&file_dialog::on_row_selected, this));
233  connect_signal_notify_modified(bookmarks_bar,
234  std::bind(&file_dialog::on_bookmark_selected, this));
235 
236  button& mkdir_button = find_widget<button>(&window, "new_dir", false);
237  button& rm_button = find_widget<button>(&window, "delete_file", false);
238  button& bookmark_add_button = find_widget<button>(&window, "add_bookmark", false);
239  button& bookmark_del_button = find_widget<button>(&window, "remove_bookmark", false);
240 
241  connect_signal_mouse_left_click(mkdir_button,
242  std::bind(&file_dialog::on_dir_create_cmd, this));
244  std::bind(&file_dialog::on_file_delete_cmd, this));
245  connect_signal_mouse_left_click(bookmark_add_button,
246  std::bind(&file_dialog::on_bookmark_add_cmd, this));
247  connect_signal_mouse_left_click(bookmark_del_button,
248  std::bind(&file_dialog::on_bookmark_del_cmd, this));
249 
250  if(read_only_) {
251  mkdir_button.set_active(false);
252  rm_button.set_active(false);
253 
255  rm_button.set_visible(widget::visibility::invisible);
256  }
257 
259 
260  window.keyboard_capture(find_widget<text_box>(&window, "filename", false, true));
261  window.add_to_keyboard_chain(&filelist);
262  window.set_exit_hook(std::bind(&file_dialog::on_exit, this, _1));
263 }
264 
266 {
267  if(window.get_retval() == FILE_DIALOG_ITEM_RETVAL) {
268  // Attempting to exit by double clicking items -- only proceeds if the item
269  // was a file.
271  window.set_retval(retval::OK, false);
272  return true;
273  } else {
274  return false;
275  }
276  }
277 
278  if(window.get_retval() == retval::OK) {
279  // Attempting to exit by pressing Enter/clicking OK -- only proceeds if the
280  // textbox was not altered by the user to point to a different directory.
281  return process_textbox_submit();
282  }
283 
284  return true;
285 }
286 
288 {
289  // TODO: Adapt for implementing directory selection mode.
290  return save_mode_
291  ? stype != SELECTION_IS_DIR && stype != SELECTION_PARENT_NOT_FOUND
292  : stype == SELECTION_IS_FILE;
293 }
294 
296 {
297  // TODO: Adapt for implementing directory selection mode.
298  if(stype != SELECTION_IS_FILE) {
299  return true;
300  }
301 
302  const std::string& message
303  = _("The file already exists. Do you wish to overwrite it?");
304  return gui2::show_message(_("Confirm"), message, message::yes_no_buttons) != gui2::retval::CANCEL;
305 }
306 
308 {
309  const auto stype = register_new_selection(name);
310 
311  //DBG_FILEDLG << "current_dir_=" << current_dir_ << " current_entry_=" << current_entry_ << '\n';
312 
313  if(is_selection_type_acceptable(stype)) {
314  return save_mode_ ? confirm_overwrite(stype) : true;
315  }
316 
317  switch(stype) {
318  case SELECTION_IS_DIR:
319  // TODO: Adapt for implementing directory selection mode.
322  break;
324  // We get here in save mode or not. Use the file creation language only in
325  // save mode.
326  if(save_mode_) {
327  show_transient_error_message(VGETTEXT("The file or folder $path cannot be created.", {{"path", name}}));
328  break;
329  }
330  FALLTHROUGH;
331  case SELECTION_NOT_FOUND:
332  // We only get here if we aren't in save mode.
333  show_transient_error_message(VGETTEXT("The file or folder $path does not exist.", {{"path", name}}));
334  break;
335  case SELECTION_IS_FILE:
336  // TODO: Adapt for implementing directory selection mode.
337  default:
338  assert(false && "Unimplemented selection mode or semantics");
339  }
340 
341  return false;
342 }
343 
345 {
346  listbox& filelist = find_widget<listbox>(get_window(), "filelist", false);
347  const std::string& selected_name = get_filelist_selection(filelist);
348  return process_submit_common(selected_name);
349 }
350 
352 {
353  text_box& file_textbox = find_widget<text_box>(get_window(), "filename", false);
354  const std::string& input_name = file_textbox.get_value();
355  return !input_name.empty() && process_submit_common(input_name);
356 }
357 
359 {
360  const int row = filelist.get_selected_row();
361 
362  if(row == -1) {
363  // Shouldn't happen...
364  return "";
365  }
366 
367  const bool i_am_root = fs::is_root(current_dir_);
368 
369  if(row == 0 && !i_am_root) {
370  return PARENT_DIR;
371  } else {
372  std::size_t n = i_am_root ? row : row - 1;
373 
374  if(n < dir_subdirs_.size()) {
375  return dir_subdirs_[n];
376  } else {
377  n -= dir_subdirs_.size();
378 
379  if(n < dir_files_.size()) {
380  return dir_files_[n];
381  } else {
382  assert(false && "File list selection is out of range!");
383  }
384  }
385  }
386 
387  return "";
388 }
389 
391 {
392  std::string new_path, new_parent;
393 
394  if(fs::is_relative(name)) {
395  // On Windows, \ represents a path relative to the root of the process'
396  // current working drive specified by the current working dir, so we get
397  // here. This makes it the only platform where is_relative() and is_root()
398  // aren't mutually exclusive.
399  if(fs::is_root(name)) {
400  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' is relative to a root resource\n";
401  // Using the browsed dir's root drive instead of the cwd's makes the most
402  // sense for users.
403  new_parent = fs::root_name(current_dir_);
404  new_path = fs::normalize_path(concat_path(new_parent, name), true, true);
405  } else {
406  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' seems relative\n";
407  new_parent = current_dir_;
408  new_path = fs::normalize_path(concat_path(current_dir_, name), true, true);
409  }
410  } else {
411  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' seems absolute\n";
412  new_parent = fs::directory_name(name);
413  new_path = fs::normalize_path(name, true, true);
414  DBG_FILEDLG << "register_new_selection(): new selection is " << new_path << '\n';
415  }
416 
417  if(!new_path.empty()) {
418  if(fs::is_directory(new_path)) {
419  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' is a directory: " << new_path << '\n';
420  current_dir_ = new_path;
421  current_entry_.clear();
422  return SELECTION_IS_DIR;
423  } else if(fs::file_exists(new_path)) {
424  // FIXME: Perhaps redundant since the three-params call to normalize_path()
425  // above necessarily validates existence.
426  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' is a file, symbolic link, or special: " << new_path << '\n';
427  current_dir_ = fs::directory_name(new_path);
428  current_entry_ = fs::base_name(new_path);
429  return SELECTION_IS_FILE;
430  }
431  }
432 
433  // The path does not exist, at least not entirely. See if the parent does
434  // (in save mode non-existent files are accepted as long as the parent dir
435  // exists).
436  const std::string& absolute_parent = fs::normalize_path(new_parent, true, true);
437  if(!absolute_parent.empty()) {
438  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' does not exist or is not accessible, but parent exists\n";
439  current_dir_ = absolute_parent;
441  return SELECTION_NOT_FOUND;
442  }
443 
444  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' does not exist or is not accessible\n";
446 }
447 
449 {
450  if(value.empty()) {
451  clear_input_text(t);
452  return;
453  }
454 
455  t.set_value(value);
456 
457  const std::size_t vallen = t.get_length();
458  const std::size_t extlen = utf8::size(extension_);
459 
460  if(save_mode_ && extlen && vallen > extlen) {
461  // Highlight everything but the extension if it matches
462  if(value.substr(vallen - extlen) == extension_) {
463  t.set_selection(0, vallen - extlen);
464  }
465  }
466 }
467 
469 {
470  if(save_mode_ && !extension_.empty()) {
472  t.set_selection(0, 0);
473  } else {
474  t.clear();
475  }
476 }
477 
479 {
481 
482  dir_files_.clear();
483  dir_subdirs_.clear();
484 
485  // TODO: Need to detect and handle cases where we don't have search permission
486  // on current_dir_, otherwise things may get weird.
488  isort_dir_entries(dir_files_);
489  isort_dir_entries(dir_subdirs_);
490 
491  //
492  // Clear and refill the filelist box.
493  //
494 
495  listbox& filelist = find_widget<listbox>(get_window(), "filelist", false);
496  button& rm_button = find_widget<button>(get_window(), "delete_file", false);
497 
498  filelist.clear();
499 
500  // Parent entry
501  if(!fs::is_root(current_dir_)) {
502  // label_parent may not necessarily be always ".." in the future, so push
503  // with check_selection = false and check the selection ourselves here.
504  push_fileview_row(filelist, label_parent, icon_parent, false);
505  if(current_entry_ == PARENT_DIR || current_entry_.empty()) {
506  filelist.select_row(0, true);
507  rm_button.set_active(false);
508  } else {
509  rm_button.set_active(true);
510  }
511  }
512 
513  for(const auto& dir : dir_subdirs_) {
514  push_fileview_row(filelist, dir, icon_dir);
515  }
516 
517  for(const auto& file : dir_files_) {
518  push_fileview_row(filelist, file, icon_file);
519  }
520 
521  find_widget<styled_widget>(get_window(), "current_dir", false).set_label(current_dir_);
522  set_input_text(find_widget<text_box>(get_window(), "filename", false), current_entry_);
523 
524  on_row_selected();
525 }
526 
527 void file_dialog::push_fileview_row(listbox& filelist, const std::string& name, const std::string& icon, bool check_selection)
528 {
529  // TODO: Hopefully some day GUI2 will allow us to make labels be ellipsized
530  // dynamically at layout/rendering time.
532  utils::ellipsis_truncate(label, FILE_DIALOG_MAX_ENTRY_LENGTH);
533 
534  std::map<std::string, string_map> data;
535  data["icon"]["label"] = icon;
536  data["file"]["label"] = label;
537 
538  grid& last_grid = filelist.add_row(data);
539 
540  //
541  // Crummy hack around the lack of an option to hook into row double click
542  // events for all rows using the GUI2 listbox API. Assign a special retval to
543  // each row that triggers a special check during dialog exit.
544  //
545  find_widget<toggle_panel>(&last_grid, "item_panel", false)
546  .set_retval(FILE_DIALOG_ITEM_RETVAL);
547 
548  if(check_selection && name == current_entry_) {
549  filelist.select_last_row(true);
550  }
551 }
552 
554 {
555  listbox& bookmarks_bar = find_widget<listbox>(get_window(), "bookmarks", false);
556 
557  // Internal state has normalized path delimiters but dot entries aren't
558  // resolved after callers call set_path(), so compare against a canonical
559  // version. The bookmark paths are already canonical, though.
560  const std::string& canon_current_dir = fs::normalize_path(current_dir_, true, true);
561 
562  // Go backwards so we can match user-defined bookmarks first (otherwise it may
563  // become impossible for the user to delete them if they match any of the
564  // predefined paths).
565  auto it = std::find(bookmark_paths_.rbegin(), bookmark_paths_.rend(), canon_current_dir);
566 
567  if(it == bookmark_paths_.rend()) {
568  if(current_bookmark_ >= 0) {
569  bookmarks_bar.select_row(static_cast<unsigned>(current_bookmark_), false);
570  }
571  current_bookmark_ = -1;
572  } else {
573  const int new_selection = static_cast<int>(std::distance(bookmark_paths_.begin(), it.base()) - 1);
574  if(new_selection != current_bookmark_) {
575  assert(static_cast<unsigned>(new_selection) < bookmarks_bar.get_item_count());
576  if(current_bookmark_ >= 0) {
577  bookmarks_bar.select_row(static_cast<unsigned>(current_bookmark_), false);
578  }
579  bookmarks_bar.select_row(static_cast<unsigned>(new_selection), true);
580  current_bookmark_ = new_selection;
581  }
582  }
583 
584  // Update bookmark edit controls.
585  button& del_button = find_widget<button>(get_window(), "remove_bookmark", false);
586 
587  if(user_bookmarks_begin_ == -1) {
588  del_button.set_active(false);
589  } else {
591  }
592 }
593 
595 {
596  listbox& filelist = find_widget<listbox>(get_window(), "filelist", false);
597  text_box& file_textbox = find_widget<text_box>(get_window(), "filename", false);
598  button& rm_button = find_widget<button>(get_window(), "delete_file", false);
599 
600  // Don't use register_new_selection() here, we don't want any parsing to be
601  // performed at this point.
603 
604  // Clear the textbox when selecting ..
605  if(current_entry_ != PARENT_DIR) {
606  set_input_text(file_textbox, current_entry_);
607  rm_button.set_active(true);
608  } else {
609  clear_input_text(file_textbox);
610  rm_button.set_active(false);
611  }
612 
613  // Need to do this every time so that input can still be sent to the
614  // textbox without clicking on it.
615  get_window()->keyboard_capture(&file_textbox);
616 }
617 
619 {
620  // Don't let us steal the focus from the primary widgets.
621  text_box& file_textbox = find_widget<text_box>(get_window(), "filename", false);
622  get_window()->keyboard_capture(&file_textbox);
623 
624  listbox& bookmarks_bar = find_widget<listbox>(get_window(), "bookmarks", false);
625  const int new_selection = bookmarks_bar.get_selected_row();
626 
627  if(new_selection < 0) {
628  if(current_bookmark_ >= 0) {
629  // Don't allow the user to deselect the selected bookmark. That wouldn't
630  // make any sense.
631  bookmarks_bar.select_row(static_cast<unsigned>(current_bookmark_));
632  }
633 
634  return;
635  }
636 
637  assert(static_cast<unsigned>(new_selection) < bookmark_paths_.size());
638  current_bookmark_ = new_selection;
639  set_path(bookmark_paths_[new_selection]);
641 
642  // Update bookmark edit controls.
643  button& del_button = find_widget<button>(get_window(), "remove_bookmark", false);
644  del_button.set_active(user_bookmarks_begin_ >= 0
645  && current_bookmark_ >= user_bookmarks_begin_);
646 }
647 
649 {
650  const std::string& default_label = fs::base_name(current_dir_);
651 
652  std::string label = default_label;
653 
654  const bool confirm = bookmark_create::execute(label);
655  if(!confirm) {
656  return;
657  }
658 
659  if(label.empty()) {
660  label = default_label;
661  }
662 
663  listbox& bookmarks_bar = find_widget<listbox>(get_window(), "bookmarks", false);
664 
666  bookmark_paths_.push_back(current_dir_);
667  const unsigned top_bookmark = bookmark_paths_.size() - 1;
668 
669  if(user_bookmarks_begin_ == -1) {
670  user_bookmarks_begin_ = top_bookmark;
671  }
672 
673  std::map<std::string, string_map> data;
674  data["bookmark"]["label"] = label;
675  bookmarks_bar.add_row(data);
676 
677  current_bookmark_ = -1;
678 
680 }
681 
683 {
684  assert(user_bookmarks_begin_ >= 0
685  && current_bookmark_ >= 0
687  && current_bookmark_ < static_cast<int>(bookmark_paths_.size()));
688 
689  listbox& bookmarks_bar = find_widget<listbox>(get_window(), "bookmarks", false);
692  bookmarks_bar.remove_row(current_bookmark_);
693 
694  current_bookmark_ = -1;
695 
697 }
698 
700 {
701  std::string new_dir_name;
702 
703  if(folder_create::execute(new_dir_name)) {
704  const std::string& new_path = concat_path(current_dir_, new_dir_name);
705 
706  if(!fs::make_directory(new_path)) {
708  VGETTEXT("Could not create a new folder at $path|. Make sure you have the appropriate permissions to write to this location.",
709  {{"path", new_path}}));
710  } else {
712  }
713  }
714 }
715 
717 {
718  if(current_entry_.empty()) {
719  return;
720  }
721 
722  const std::string& selection = concat_path(current_dir_, current_entry_);
723  const bool is_dir = fs::is_directory(selection);
724 
725  const std::string& message = (is_dir
726  ? _("The following folder and its contents will be permanently deleted:")
727  : _("The following file will be permanently deleted:"))
728  + "\n\n" + selection + "\n\n" + _("Do you wish to continue?");
729 
731  return;
732  }
733 
734  const bool result = is_dir
735  ? fs::delete_directory(selection)
736  : fs::delete_file(selection);
737 
738  if(!result) {
740  VGETTEXT("Could not delete $path|. Make sure you have the appropriate permissions to write to this location.",
741  {{"path", selection}}));
742  } else {
744  }
745 }
746 
747 } // namespace dialogs
748 } // namespace gui2
void push_fileview_row(class listbox &filelist, const std::string &name, const std::string &icon, bool check_selection=true)
Row building helper for refresh_fileview().
void keyboard_capture(widget *widget)
Definition: window.cpp:1282
Dialog was closed with the CANCEL button.
Definition: retval.hpp:37
bool delete_directory(const std::string &dirname, const bool keep_pbl)
Definition: filesystem.cpp:951
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:152
void on_bookmark_add_cmd()
Handles Add Bookmark button press events.
void set_selection(std::size_t start, int length)
Sets or clears the text selection.
void set_input_text(class text_box &t, const std::string &value)
std::vector< std::string > dir_subdirs_
std::string get_filelist_selection(class listbox &filelist)
void remove_user_bookmark(unsigned index)
Definition: paths.cpp:254
bool delete_file(const std::string &filename)
Definition: filesystem.cpp:990
file_dialog & set_path(const std::string &value)
Sets the initial file selection.
Main class to show messages to the user.
Definition: message.hpp:34
void clear_input_text(class text_box &t)
#define a
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:267
std::string get_value() const
This file contains the window object, this object is a top level container which has the event manage...
static bool execute(std::string &bookmark_name)
The execute function; see modal_dialog for more information.
void ellipsis_truncate(std::string &str, const std::size_t size)
Truncates a string to a given utf-8 character count and then appends an ellipsis. ...
std::vector< bookmark_info > user_bookmarks()
Definition: paths.cpp:266
window * get_window() const
Returns a pointer to the dialog&#39;s window.
bool select_last_row(const bool select=true)
Does exactly as advertised: selects the list&#39;s last row.
Definition: listbox.hpp:194
Label showing a text.
Definition: label.hpp:32
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:277
std::string normalize_path(const std::string &fpath, bool normalize_separators, bool resolve_dot_entries)
Returns the absolute path of a file.
static lg::log_domain log_filedlg
Definition: file_dialog.cpp:39
void refresh_fileview()
Updates the dialog contents to match the internal state.
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:252
Class for a single line text area.
Definition: text_box.hpp:121
std::vector< path_info > game_paths(unsigned path_types)
Returns a list of game-related paths.
Definition: paths.cpp:190
Generic file dialog.
Definition: field-fwd.hpp:22
#define b
void on_bookmark_del_cmd()
Handles Remove Bookmark button press events.
std::string path() const
Gets the current file selection.
virtual void set_label(const t_string &label)
The listbox class.
Definition: listbox.hpp:42
Base container class.
Definition: grid.hpp:30
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:100
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
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 clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:127
void set_visible(const visibility visible)
Definition: widget.cpp:475
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
std::vector< path_info > system_paths(unsigned path_types)
Returns a list of system-defined paths.
Definition: paths.cpp:218
const std::string & title() const
Gets the current dialog title text.
Definition: file_dialog.hpp:48
std::string root_name(const std::string &path)
Returns the name of the root device if included in the given path.
file_dialog & set_filename(const std::string &value)
Sets the initial file name input but not the path.
std::string nearest_extant_parent(const std::string &file)
Finds the nearest parent in existence for a file or directory.
std::vector< std::string > dir_files_
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
#define DBG_FILEDLG
Definition: file_dialog.cpp:43
bool confirm_overwrite(SELECTION_TYPE stype)
Prompts the user before overwriting an existing file.
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:133
Shows a yes and no button.
Definition: message.hpp:79
Desktop paths, storage media and bookmark functions.
SELECTION_TYPE register_new_selection(const std::string &name)
Updates the internal state and returns the type of the selection.
Various uncategorised dialogs.
int get_retval()
Definition: window.hpp:370
bool process_fileview_submit()
Processes file view selection in reaction to row double-click events.
bool is_path_sep(char c)
Returns whether c is a path separator.
std::size_t get_length() const
bool on_exit(window &window)
Handles dialog exit events and decides whether to proceed or not.
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, file_name_option mode, file_filter_option filter, file_reorder_option reorder, file_tree_checksum *checksum)
Populates &#39;files&#39; with all the files and &#39;dirs&#39; with all the directories in dir.
Definition: filesystem.cpp:353
bool is_relative(const std::string &path)
Returns whether the path seems to be relative.
The user set the widget invisible, that means:
unsigned add_user_bookmark(const std::string &label, const std::string &path)
Definition: paths.cpp:241
bool make_directory(const std::string &dirname)
Definition: filesystem.cpp:940
std::string name
Definition: sdl_ttf.cpp:70
void on_bookmark_selected()
Handles selection or deselection of bookmarks.
bool is_root(const std::string &path)
Returns whether the path is the root of the file hierarchy.
std::vector< std::string > bookmark_paths_
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
Declarations for File-IO.
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition: window.hpp:363
Base class for all visible items.
static int sort(lua_State *L)
Definition: ltablib.cpp:411
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
void on_row_selected()
Handles file/directory selection on single-click.
bool process_textbox_submit()
Processes textbox input in reaction to OK button/Enter key events.
char path_separator()
Returns the standard path separator for the current platform.
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
virtual void set_value(const std::string &text)
The set_value is virtual for the password_box class.
void show_transient_error_message(const std::string &message, const std::string &image, const bool message_use_markup)
Shows a transient error message to the user.
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: button.cpp:62
double t
Definition: astarsearch.cpp:64
int icompare(const std::string &s1, const std::string &s2)
Case-insensitive lexicographical comparison.
Definition: gettext.cpp:475
void sync_bookmarks_bar()
Updates the bookmarks bar state to reflect the internal state.
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:88
bool process_submit_common(const std::string &name)
void on_dir_create_cmd()
Handles New Folder button press events.
void on_file_delete_cmd()
Handles Delete button press events.
Dialog was closed with the OK button.
Definition: retval.hpp:34
static map_location::DIRECTION n
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
virtual void pre_show(window &window) override
Inherited from modal_dialog.
bool is_selection_type_acceptable(SELECTION_TYPE stype) const
Returns whether the given selection type is acceptable for closing the dialog.
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.