The Battle for Wesnoth  1.15.12+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::dialogs
100 {
101 
102 REGISTER_DIALOG(file_dialog)
103 
105  : title_(_("Find File"))
106  , msg_()
107  , ok_label_()
108  , extension_()
109  , current_entry_()
110  , current_dir_()
111  , read_only_(false)
112  , save_mode_(false)
113  , dir_files_()
114  , dir_subdirs_()
115  , bookmark_paths_()
116  , current_bookmark_()
117  , user_bookmarks_begin_()
118 {
119  set_restore(true);
120 }
121 
122 std::string file_dialog::path() const
123 {
124  const std::string& dir_norm = fs::normalize_path(current_dir_, true);
125 
126  if(current_entry_.empty() || current_entry_ == CURRENT_DIR) {
127  return dir_norm;
128  } else if(current_entry_ == PARENT_DIR) {
129  return fs::directory_name(dir_norm);
130  }
131 
132  return concat_path(dir_norm, current_entry_);
133 }
134 
135 file_dialog& file_dialog::set_path(const std::string& value)
136 {
137  if(value.empty()) {
138  current_dir_ = filesystem_root();
139  }
140 
141  const std::string& norm = fs::normalize_path(value, true);
142 
143  if(fs::is_directory(norm)) {
144  current_dir_ = norm;
145  } else {
147  if(current_dir_.empty()) {
148  current_dir_ = filesystem_root();
149  }
150  // The file may or may not exist. We'll find out eventually when setting up
151  // the dialog.
153  }
154 
155  return *this;
156 }
157 
158 file_dialog& file_dialog::set_filename(const std::string& value)
159 {
160  current_entry_ = value;
161 
162  return *this;
163 }
164 
166 {
167  styled_widget& title = find_widget<styled_widget>(&window, "title", false);
168  styled_widget& message = find_widget<styled_widget>(&window, "message", false);
169  styled_widget& ok = find_widget<styled_widget>(&window, "ok", false);
170 
171  title.set_label(title_);
172 
173  if(msg_.empty()) {
174  message.set_visible(gui2::widget::visibility::invisible);
175  } else {
176  message.set_label(msg_);
177  message.set_use_markup(true);
178  }
179 
180  if(ok_label_.empty()) {
181  ok.set_label(save_mode_ ? _("Save") : _("Open"));
182  } else {
183  ok.set_label(ok_label_);
184  }
185 
186  listbox& bookmarks_bar = find_widget<listbox>(&window, "bookmarks", false);
187 
188  find_widget<styled_widget>(&window, "current_dir", false).set_text_ellipse_mode(PANGO_ELLIPSIZE_START);
189 
190  //
191  // Push hard-coded bookmarks.
192  //
193 
194  std::vector<desktop::path_info> bookmarks = desktop::game_paths();
195  const auto& sys_paths = desktop::system_paths();
196  bookmarks.insert(bookmarks.end(), sys_paths.begin(), sys_paths.end());
197 
198  bookmark_paths_.clear();
200 
201  std::map<std::string, string_map> data;
202 
203  for(const auto& pinfo : bookmarks) {
204  bookmark_paths_.push_back(pinfo.path);
205  data["bookmark"]["label"] = pinfo.display_name();
206  bookmarks_bar.add_row(data);
207  }
208 
209  //
210  // Push user-defined bookmarks.
211  //
212 
213  const std::vector<desktop::bookmark_info>& user_bookmarks = desktop::user_bookmarks();
214 
215  if(!user_bookmarks.empty()) {
217  }
218 
219  for(const auto& bookmark : user_bookmarks) {
220  bookmark_paths_.push_back(bookmark.path);
221  data["bookmark"]["label"] = bookmark.label;
222  bookmarks_bar.add_row(data);
223  }
224 
226 
227  listbox& filelist = find_widget<listbox>(&window, "filelist", false);
228 
230  std::bind(&file_dialog::on_row_selected, this));
231  connect_signal_notify_modified(bookmarks_bar,
232  std::bind(&file_dialog::on_bookmark_selected, this));
233 
234  button& mkdir_button = find_widget<button>(&window, "new_dir", false);
235  button& rm_button = find_widget<button>(&window, "delete_file", false);
236  button& bookmark_add_button = find_widget<button>(&window, "add_bookmark", false);
237  button& bookmark_del_button = find_widget<button>(&window, "remove_bookmark", false);
238 
239  connect_signal_mouse_left_click(mkdir_button,
240  std::bind(&file_dialog::on_dir_create_cmd, this));
242  std::bind(&file_dialog::on_file_delete_cmd, this));
243  connect_signal_mouse_left_click(bookmark_add_button,
244  std::bind(&file_dialog::on_bookmark_add_cmd, this));
245  connect_signal_mouse_left_click(bookmark_del_button,
246  std::bind(&file_dialog::on_bookmark_del_cmd, this));
247 
248  if(read_only_) {
249  mkdir_button.set_active(false);
250  rm_button.set_active(false);
251 
253  rm_button.set_visible(widget::visibility::invisible);
254  }
255 
257 
258  window.keyboard_capture(find_widget<text_box>(&window, "filename", false, true));
259  window.add_to_keyboard_chain(&filelist);
260  window.set_exit_hook(std::bind(&file_dialog::on_exit, this, std::placeholders::_1));
261 }
262 
264 {
265  if(window.get_retval() == FILE_DIALOG_ITEM_RETVAL) {
266  // Attempting to exit by double clicking items -- only proceeds if the item
267  // was a file.
269  window.set_retval(retval::OK, false);
270  return true;
271  } else {
272  return false;
273  }
274  }
275 
276  if(window.get_retval() == retval::OK) {
277  // Attempting to exit by pressing Enter/clicking OK -- only proceeds if the
278  // textbox was not altered by the user to point to a different directory.
279  return process_textbox_submit();
280  }
281 
282  return true;
283 }
284 
286 {
287  // TODO: Adapt for implementing directory selection mode.
288  return save_mode_
289  ? stype != SELECTION_IS_DIR && stype != SELECTION_PARENT_NOT_FOUND
290  : stype == SELECTION_IS_FILE;
291 }
292 
294 {
295  // TODO: Adapt for implementing directory selection mode.
296  if(stype != SELECTION_IS_FILE) {
297  return true;
298  }
299 
300  const std::string& message
301  = _("The file already exists. Do you wish to overwrite it?");
302  return gui2::show_message(_("Confirm"), message, message::yes_no_buttons) != gui2::retval::CANCEL;
303 }
304 
305 bool file_dialog::process_submit_common(const std::string& name)
306 {
307  const auto stype = register_new_selection(name);
308 
309  //DBG_FILEDLG << "current_dir_=" << current_dir_ << " current_entry_=" << current_entry_ << '\n';
310 
311  if(is_selection_type_acceptable(stype)) {
312  return save_mode_ ? confirm_overwrite(stype) : true;
313  }
314 
315  switch(stype) {
316  case SELECTION_IS_DIR:
317  // TODO: Adapt for implementing directory selection mode.
320  break;
322  // We get here in save mode or not. Use the file creation language only in
323  // save mode.
324  if(save_mode_) {
325  show_transient_error_message(VGETTEXT("The file or folder $path cannot be created.", {{"path", name}}));
326  break;
327  }
328  [[fallthrough]];
329  case SELECTION_NOT_FOUND:
330  // We only get here if we aren't in save mode.
331  show_transient_error_message(VGETTEXT("The file or folder $path does not exist.", {{"path", name}}));
332  break;
333  case SELECTION_IS_FILE:
334  // TODO: Adapt for implementing directory selection mode.
335  default:
336  assert(false && "Unimplemented selection mode or semantics");
337  }
338 
339  return false;
340 }
341 
343 {
344  listbox& filelist = find_widget<listbox>(get_window(), "filelist", false);
345  const std::string& selected_name = get_filelist_selection(filelist);
346  return process_submit_common(selected_name);
347 }
348 
350 {
351  text_box& file_textbox = find_widget<text_box>(get_window(), "filename", false);
352  const std::string& input_name = file_textbox.get_value();
353  return !input_name.empty() && process_submit_common(input_name);
354 }
355 
357 {
358  const int row = filelist.get_selected_row();
359 
360  if(row == -1) {
361  // Shouldn't happen...
362  return "";
363  }
364 
365  const bool i_am_root = fs::is_root(current_dir_);
366 
367  if(row == 0 && !i_am_root) {
368  return PARENT_DIR;
369  } else {
370  std::size_t n = i_am_root ? row : row - 1;
371 
372  if(n < dir_subdirs_.size()) {
373  return dir_subdirs_[n];
374  } else {
375  n -= dir_subdirs_.size();
376 
377  if(n < dir_files_.size()) {
378  return dir_files_[n];
379  } else {
380  assert(false && "File list selection is out of range!");
381  }
382  }
383  }
384 
385  return "";
386 }
387 
389 {
390  std::string new_path, new_parent;
391 
392  if(fs::is_relative(name)) {
393  // On Windows, \ represents a path relative to the root of the process'
394  // current working drive specified by the current working dir, so we get
395  // here. This makes it the only platform where is_relative() and is_root()
396  // aren't mutually exclusive.
397  if(fs::is_root(name)) {
398  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' is relative to a root resource\n";
399  // Using the browsed dir's root drive instead of the cwd's makes the most
400  // sense for users.
401  new_parent = fs::root_name(current_dir_);
402  new_path = fs::normalize_path(concat_path(new_parent, name), true, true);
403  } else {
404  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' seems relative\n";
405  new_parent = current_dir_;
406  new_path = fs::normalize_path(concat_path(current_dir_, name), true, true);
407  }
408  } else {
409  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' seems absolute\n";
410  new_parent = fs::directory_name(name);
411  new_path = fs::normalize_path(name, true, true);
412  DBG_FILEDLG << "register_new_selection(): new selection is " << new_path << '\n';
413  }
414 
415  if(!new_path.empty()) {
416  if(fs::is_directory(new_path)) {
417  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' is a directory: " << new_path << '\n';
418  current_dir_ = new_path;
419  current_entry_.clear();
420  return SELECTION_IS_DIR;
421  } else if(fs::file_exists(new_path)) {
422  // FIXME: Perhaps redundant since the three-params call to normalize_path()
423  // above necessarily validates existence.
424  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' is a file, symbolic link, or special: " << new_path << '\n';
425  current_dir_ = fs::directory_name(new_path);
426  current_entry_ = fs::base_name(new_path);
427  return SELECTION_IS_FILE;
428  }
429  }
430 
431  // The path does not exist, at least not entirely. See if the parent does
432  // (in save mode non-existent files are accepted as long as the parent dir
433  // exists).
434  const std::string& absolute_parent = fs::normalize_path(new_parent, true, true);
435  if(!absolute_parent.empty()) {
436  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' does not exist or is not accessible, but parent exists\n";
437  current_dir_ = absolute_parent;
439  return SELECTION_NOT_FOUND;
440  }
441 
442  DBG_FILEDLG << "register_new_selection(): new selection '" << name << "' does not exist or is not accessible\n";
444 }
445 
446 void file_dialog::set_input_text(text_box& t, const std::string& value)
447 {
448  if(value.empty()) {
449  clear_input_text(t);
450  return;
451  }
452 
453  t.set_value(value);
454 
455  const std::size_t vallen = t.get_length();
456  const std::size_t extlen = utf8::size(extension_);
457 
458  if(save_mode_ && extlen && vallen > extlen) {
459  // Highlight everything but the extension if it matches
460  if(value.substr(vallen - extlen) == extension_) {
461  t.set_selection(0, vallen - extlen);
462  }
463  }
464 }
465 
467 {
468  if(save_mode_ && !extension_.empty()) {
470  t.set_selection(0, 0);
471  } else {
472  t.clear();
473  }
474 }
475 
477 {
479 
480  dir_files_.clear();
481  dir_subdirs_.clear();
482 
483  // TODO: Need to detect and handle cases where we don't have search permission
484  // on current_dir_, otherwise things may get weird.
486  isort_dir_entries(dir_files_);
487  isort_dir_entries(dir_subdirs_);
488 
489  //
490  // Clear and refill the filelist box.
491  //
492 
493  listbox& filelist = find_widget<listbox>(get_window(), "filelist", false);
494  button& rm_button = find_widget<button>(get_window(), "delete_file", false);
495 
496  filelist.clear();
497 
498  // Parent entry
499  if(!fs::is_root(current_dir_)) {
500  // label_parent may not necessarily be always ".." in the future, so push
501  // with check_selection = false and check the selection ourselves here.
502  push_fileview_row(filelist, label_parent, icon_parent, false);
503  if(current_entry_ == PARENT_DIR || current_entry_.empty()) {
504  filelist.select_row(0, true);
505  rm_button.set_active(false);
506  } else {
507  rm_button.set_active(true);
508  }
509  }
510 
511  for(const auto& dir : dir_subdirs_) {
512  push_fileview_row(filelist, dir, icon_dir);
513  }
514 
515  for(const auto& file : dir_files_) {
516  push_fileview_row(filelist, file, icon_file);
517  }
518 
519  find_widget<styled_widget>(get_window(), "current_dir", false).set_label(current_dir_);
520  set_input_text(find_widget<text_box>(get_window(), "filename", false), current_entry_);
521 
522  on_row_selected();
523 }
524 
525 void file_dialog::push_fileview_row(listbox& filelist, const std::string& name, const std::string& icon, bool check_selection)
526 {
527  // TODO: Hopefully some day GUI2 will allow us to make labels be ellipsized
528  // dynamically at layout/rendering time.
529  std::string label = name;
530  utils::ellipsis_truncate(label, FILE_DIALOG_MAX_ENTRY_LENGTH);
531 
532  std::map<std::string, string_map> data;
533  data["icon"]["label"] = icon;
534  data["file"]["label"] = label;
535 
536  grid& last_grid = filelist.add_row(data);
537 
538  //
539  // Crummy hack around the lack of an option to hook into row double click
540  // events for all rows using the GUI2 listbox API. Assign a special retval to
541  // each row that triggers a special check during dialog exit.
542  //
543  find_widget<toggle_panel>(&last_grid, "item_panel", false)
544  .set_retval(FILE_DIALOG_ITEM_RETVAL);
545 
546  if(check_selection && name == current_entry_) {
547  filelist.select_last_row(true);
548  }
549 }
550 
552 {
553  listbox& bookmarks_bar = find_widget<listbox>(get_window(), "bookmarks", false);
554 
555  // Internal state has normalized path delimiters but dot entries aren't
556  // resolved after callers call set_path(), so compare against a canonical
557  // version. The bookmark paths are already canonical, though.
558  const std::string& canon_current_dir = fs::normalize_path(current_dir_, true, true);
559 
560  // Go backwards so we can match user-defined bookmarks first (otherwise it may
561  // become impossible for the user to delete them if they match any of the
562  // predefined paths).
563  auto it = std::find(bookmark_paths_.rbegin(), bookmark_paths_.rend(), canon_current_dir);
564 
565  if(it == bookmark_paths_.rend()) {
566  if(current_bookmark_ >= 0) {
567  bookmarks_bar.select_row(static_cast<unsigned>(current_bookmark_), false);
568  }
569  current_bookmark_ = -1;
570  } else {
571  const int new_selection = static_cast<int>(std::distance(bookmark_paths_.begin(), it.base()) - 1);
572  if(new_selection != current_bookmark_) {
573  assert(static_cast<unsigned>(new_selection) < bookmarks_bar.get_item_count());
574  if(current_bookmark_ >= 0) {
575  bookmarks_bar.select_row(static_cast<unsigned>(current_bookmark_), false);
576  }
577  bookmarks_bar.select_row(static_cast<unsigned>(new_selection), true);
578  current_bookmark_ = new_selection;
579  }
580  }
581 
582  // Update bookmark edit controls.
583  button& del_button = find_widget<button>(get_window(), "remove_bookmark", false);
584 
585  if(user_bookmarks_begin_ == -1) {
586  del_button.set_active(false);
587  } else {
589  }
590 }
591 
593 {
594  listbox& filelist = find_widget<listbox>(get_window(), "filelist", false);
595  text_box& file_textbox = find_widget<text_box>(get_window(), "filename", false);
596  button& rm_button = find_widget<button>(get_window(), "delete_file", false);
597 
598  // Don't use register_new_selection() here, we don't want any parsing to be
599  // performed at this point.
601 
602  // Clear the textbox when selecting ..
603  if(current_entry_ != PARENT_DIR) {
604  set_input_text(file_textbox, current_entry_);
605  rm_button.set_active(true);
606  } else {
607  clear_input_text(file_textbox);
608  rm_button.set_active(false);
609  }
610 
611  // Need to do this every time so that input can still be sent to the
612  // textbox without clicking on it.
613  get_window()->keyboard_capture(&file_textbox);
614 }
615 
617 {
618  // Don't let us steal the focus from the primary widgets.
619  text_box& file_textbox = find_widget<text_box>(get_window(), "filename", false);
620  get_window()->keyboard_capture(&file_textbox);
621 
622  listbox& bookmarks_bar = find_widget<listbox>(get_window(), "bookmarks", false);
623  const int new_selection = bookmarks_bar.get_selected_row();
624 
625  if(new_selection < 0) {
626  if(current_bookmark_ >= 0) {
627  // Don't allow the user to deselect the selected bookmark. That wouldn't
628  // make any sense.
629  bookmarks_bar.select_row(static_cast<unsigned>(current_bookmark_));
630  }
631 
632  return;
633  }
634 
635  assert(static_cast<unsigned>(new_selection) < bookmark_paths_.size());
636  current_bookmark_ = new_selection;
637  set_path(bookmark_paths_[new_selection]);
639 
640  // Update bookmark edit controls.
641  button& del_button = find_widget<button>(get_window(), "remove_bookmark", false);
642  del_button.set_active(user_bookmarks_begin_ >= 0
643  && current_bookmark_ >= user_bookmarks_begin_);
644 }
645 
647 {
648  const std::string& default_label = fs::base_name(current_dir_);
649 
650  std::string label = default_label;
651 
652  const bool confirm = bookmark_create::execute(label);
653  if(!confirm) {
654  return;
655  }
656 
657  if(label.empty()) {
658  label = default_label;
659  }
660 
661  listbox& bookmarks_bar = find_widget<listbox>(get_window(), "bookmarks", false);
662 
664  bookmark_paths_.push_back(current_dir_);
665  const unsigned top_bookmark = bookmark_paths_.size() - 1;
666 
667  if(user_bookmarks_begin_ == -1) {
668  user_bookmarks_begin_ = top_bookmark;
669  }
670 
671  std::map<std::string, string_map> data;
672  data["bookmark"]["label"] = label;
673  bookmarks_bar.add_row(data);
674 
675  current_bookmark_ = -1;
676 
678 }
679 
681 {
682  assert(user_bookmarks_begin_ >= 0
683  && current_bookmark_ >= 0
685  && current_bookmark_ < static_cast<int>(bookmark_paths_.size()));
686 
687  listbox& bookmarks_bar = find_widget<listbox>(get_window(), "bookmarks", false);
690  bookmarks_bar.remove_row(current_bookmark_);
691 
692  current_bookmark_ = -1;
693 
695 }
696 
698 {
699  std::string new_dir_name;
700 
701  if(folder_create::execute(new_dir_name)) {
702  const std::string& new_path = concat_path(current_dir_, new_dir_name);
703 
704  if(!fs::make_directory(new_path)) {
706  VGETTEXT("Could not create a new folder at $path|. Make sure you have the appropriate permissions to write to this location.",
707  {{"path", new_path}}));
708  } else {
710  }
711  }
712 }
713 
715 {
716  if(current_entry_.empty()) {
717  return;
718  }
719 
720  const std::string& selection = concat_path(current_dir_, current_entry_);
721  const bool is_dir = fs::is_directory(selection);
722 
723  const std::string& message = (is_dir
724  ? _("The following folder and its contents will be permanently deleted:")
725  : _("The following file will be permanently deleted:"))
726  + "\n\n" + selection + "\n\n" + _("Do you wish to continue?");
727 
729  return;
730  }
731 
732  const bool result = is_dir
733  ? fs::delete_directory(selection)
734  : fs::delete_file(selection);
735 
736  if(!result) {
738  VGETTEXT("Could not delete $path|. Make sure you have the appropriate permissions to write to this location.",
739  {{"path", selection}}));
740  } else {
742  }
743 }
744 
745 } // namespace dialogs
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:1273
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:945
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:984
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:263
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
A label displays a text, the text can be wrapped but no scrollbars are provided.
Definition: label.hpp:56
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:276
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
static std::string _(const char *str)
Definition: gettext.hpp:92
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:251
Class for a single line text area.
Definition: text_box.hpp:140
std::vector< path_info > game_paths(unsigned path_types)
Returns a list of game-related paths.
Definition: paths.cpp:190
#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
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:126
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
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode 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:349
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:132
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.
int get_retval()
Definition: window.hpp:364
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.
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:934
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:67
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:357
Base class for all visible items.
static int sort(lua_State *L)
Definition: ltablib.cpp:397
#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:474
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:87
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
void set_retval(int retval)
Convenience wrapper to set the window&#39;s exit code.
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:64
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
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.