widgets/file_menu.cpp

Go to the documentation of this file.
00001 /* $Id: file_menu.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2003 - 2012 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #include "global.hpp"
00017 
00018 #define GETTEXT_DOMAIN "wesnoth-lib"
00019 
00020 #include "filesystem.hpp"
00021 #include "marked-up_text.hpp"
00022 #include "wml_separators.hpp"
00023 #include "widgets/file_menu.hpp"
00024 
00025 
00026 namespace {
00027     std::vector<std::string> empty_string_vector;
00028 }
00029 
00030 namespace gui {
00031 
00032 static const std::string dir_picture("misc/folder-icon.png");
00033 static const std::string path_up("..");
00034 const char file_menu::path_delim('/');
00035 
00036 file_menu::file_menu(CVideo &disp, std::string start_file)
00037     : menu(disp, empty_string_vector, false),
00038       current_dir_(get_path(start_file)),
00039       chosen_file_(start_file), last_selection_(-1),
00040       type_a_head_(-1)
00041 {
00042     // If the start file is not a file or directory, use the root.
00043     if((!file_exists(chosen_file_) && !::is_directory(chosen_file_))
00044         || !::is_directory(current_dir_)) {
00045         current_dir_ = path_delim;
00046         chosen_file_ = current_dir_;
00047     }
00048     // FIXME: quick hack
00049     // on a high-res screen the initial max_items_onscreen is based
00050     // on .66 of y dimension, eg. 17 menu items, exceeding the
00051     // starting box which can only take 13 or so: force it to be smaller
00052 //  set_measurements(400, 384);
00053     update_file_lists();
00054 }
00055 
00056 void file_menu::display_current_files() {
00057     std::vector<std::string> to_show;
00058     if (!is_root(current_dir_)) {
00059         to_show.push_back(path_up);
00060     }
00061     std::vector<std::string>::iterator it;
00062     for (it = dirs_in_current_dir_.begin(); it != dirs_in_current_dir_.end(); ++it) {
00063         // Add an image to show that these are directories.
00064         std::stringstream ss;
00065         ss << font::IMAGE << dir_picture << COLUMN_SEPARATOR << *it;
00066         to_show.push_back(ss.str());
00067     }
00068     for (it = files_in_current_dir_.begin(); it != files_in_current_dir_.end(); ++it) {
00069         const std::string display_string = COLUMN_SEPARATOR + *it;
00070         to_show.push_back(display_string);
00071     }
00072     const int menu_font_size = font::SIZE_NORMAL; // Known from menu.cpp.
00073     for (it = to_show.begin(); it != to_show.end(); ++it) {
00074         // Make sure that all lines fit.
00075         // Guess the width of the scrollbar to be 30 since it is not accessible from here.
00076         // -25 to compensate for the picture column.
00077         while(static_cast<unsigned int>(
00078                 font::line_width(*it, menu_font_size)) > width() - 30 - 25) {
00079 
00080             (*it).resize((*it).size() - 1);
00081         }
00082     }
00083     set_items(to_show);
00084 }
00085 
00086 int file_menu::delete_chosen_file() {
00087     const int ret = remove(chosen_file_.c_str());
00088     if (ret == -1) {
00089     //  gui2::show_transient_message(disp_.video(), "", _("Deletion of the file failed."));
00090     }
00091     else {
00092         last_selection_ = -1;
00093         update_file_lists();
00094         chosen_file_ = current_dir_;
00095     }
00096     return ret;
00097 }
00098 
00099 bool file_menu::make_directory(const std::string& subdir_name) {
00100     bool ret = ::make_directory(add_path(current_dir_, subdir_name));
00101     if (ret == false) {
00102     //  gui2::show_transient_message(disp_.video(), "", _("Creation of the directory failed."));
00103     }
00104     else {
00105         last_selection_ = -1;
00106         update_file_lists();
00107         chosen_file_ = current_dir_;
00108     }
00109     return ret;
00110 }
00111 
00112 void file_menu::handle_event(const SDL_Event& event) {
00113     menu::handle_event(event);
00114 
00115     if(selection() != last_selection_
00116             && !type_a_head()) {
00117         type_a_head_ = -1;
00118         entry_selected(selection());
00119         last_selection_ = selection();
00120     }
00121 }
00122 
00123 void file_menu::entry_selected(const unsigned entry) {
00124     const int entry_index = entry - (is_root(current_dir_) ? 0 : 1);
00125     if (entry_index >= 0) {
00126         std::string selected;
00127         if(static_cast<unsigned>(entry_index) < dirs_in_current_dir_.size()) {
00128             const int dir_index = entry_index;
00129             selected = dirs_in_current_dir_[dir_index];
00130         }
00131         else {
00132             const int file_index = entry_index - dirs_in_current_dir_.size();
00133             if(file_index >= 0 && size_t(file_index) < files_in_current_dir_.size()) {
00134                 selected = files_in_current_dir_[file_index];
00135             } else {
00136                 return;
00137             }
00138         }
00139         chosen_file_ = add_path(current_dir_, selected);
00140     } else {
00141         chosen_file_ = path_up;
00142     }
00143 }
00144 
00145 bool file_menu::is_directory(const std::string& fname) const {
00146     if(fname == path_up)
00147         return true;
00148     return ::is_directory(fname);
00149 }
00150 
00151 void file_menu::change_directory(const std::string& path) {
00152     if(path == path_up)
00153     {
00154         // Parent dir wanted.
00155         if (!is_root(current_dir_)) {
00156             current_dir_ = get_path_up(current_dir_);
00157             last_selection_ = -1;
00158             update_file_lists();
00159             chosen_file_ = current_dir_;
00160         }
00161         else {
00162             return;
00163         }
00164 
00165     } else {
00166         current_dir_ = path;
00167         chosen_file_ = current_dir_;
00168         last_selection_ = -1;
00169         update_file_lists();
00170     }
00171 }
00172 
00173 std::string file_menu::get_choice() const {
00174     return chosen_file_;
00175 }
00176 
00177 
00178 std::string file_menu::get_path(const std::string& file_or_dir) const {
00179     std::string res_path = file_or_dir;
00180     if (!::is_directory(file_or_dir)) {
00181         size_t index = file_or_dir.find_last_of(path_delim);
00182         if (index != std::string::npos) {
00183             res_path = file_or_dir.substr(0, index);
00184         }
00185     }
00186     return res_path;
00187 }
00188 
00189 std::string file_menu::get_path_up(const std::string& path, const unsigned levels) const {
00190     std::string curr_path = get_path(path);
00191     for (unsigned i = 0; i < levels; i++) {
00192         if (is_root(curr_path)) {
00193             break;
00194         }
00195         curr_path = strip_last_delim(curr_path);
00196         size_t index = curr_path.find_last_of(path_delim);
00197         if (index != std::string::npos) {
00198             curr_path = curr_path.substr(0, index);
00199         }
00200         else {
00201 #ifdef __AMIGAOS4__
00202             index = curr_path.find_last_of(':');
00203             if (index != std::string::npos) index++;
00204 #endif
00205             break;
00206         }
00207     }
00208     if (curr_path.empty()) {
00209         // The root was reached, represent this as one delimiter only.
00210         curr_path = path_delim;
00211     }
00212 #ifdef _WIN32
00213     if (curr_path.size() == 2 && curr_path[1] == ':') curr_path += path_delim;
00214 #endif
00215     return curr_path;
00216 }
00217 
00218 std::string file_menu::strip_last_delim(const std::string& path) const {
00219     std::string res_string = path;
00220     if (path[path.size() - 1] == path_delim) {
00221         res_string = path.substr(0, path.size() - 1);
00222     }
00223     return res_string;
00224 }
00225 
00226 bool file_menu::is_root(const std::string& path) const {
00227 #ifdef __AMIGAOS4__
00228     return path.empty() || path[path.size()-1] == ':';
00229 #else
00230     return path.empty() || (path.size() == 1 && path[0] == path_delim);
00231 #endif
00232 }
00233 
00234 std::string file_menu::add_path(const std::string& path, const std::string& to_add) const
00235 {
00236     std::string joined_path = strip_last_delim(path);
00237     if (!to_add.empty()) {
00238         if (to_add == path_up) {
00239             return get_path_up(path);
00240         }
00241 #ifdef __AMIGAOS4__
00242         else if (joined_path.empty() || joined_path[joined_path.size()-1] == ':') {
00243             if (to_add[0] == path_delim)
00244                 joined_path += to_add.substr(1);
00245             else
00246                 joined_path += to_add;
00247         }
00248 #endif
00249 #ifdef _WIN32
00250         else if (to_add.size() > 1 && to_add[1] == ':') {
00251             joined_path = to_add;
00252         }
00253 #else
00254         else if (to_add[0] == path_delim) {
00255             joined_path = to_add;
00256         }
00257 #endif
00258         else {
00259             joined_path += "/" + to_add;
00260         }
00261     }
00262     return joined_path;
00263 }
00264 
00265 struct match_begin {
00266     match_begin(const std::string& begin) : begin_(begin)
00267     {}
00268 
00269     bool operator()(const std::string& o) const
00270     {
00271         return o.compare(0, begin_.size(), begin_) == 0;
00272     }
00273 
00274     private:
00275     const std::string& begin_;
00276 };
00277 
00278 bool file_menu::type_a_head() const
00279 {
00280     return selection() == type_a_head_;
00281 }
00282 
00283 void file_menu::reset_type_a_head()
00284 {
00285     if (type_a_head_ >= 0)
00286     {
00287         entry_selected(type_a_head_);
00288         last_selection_ = type_a_head_;
00289     }
00290     type_a_head_ = -1;
00291 }
00292 
00293 void file_menu::select_file(const std::string& begin_of_filename)
00294 {
00295     size_t additional_index = is_root(current_dir_) ? 0 : 1;
00296     std::vector<std::string>::iterator it;
00297     it = std::find_if(dirs_in_current_dir_.begin(), dirs_in_current_dir_.end(), match_begin(begin_of_filename));
00298     if (it != dirs_in_current_dir_.end())
00299     {
00300         type_a_head_ = additional_index + it - dirs_in_current_dir_.begin();
00301         move_selection(type_a_head_);
00302         return;
00303     }
00304     additional_index += dirs_in_current_dir_.size();
00305 
00306     it = std::find_if(files_in_current_dir_.begin(), files_in_current_dir_.end(), match_begin(begin_of_filename));
00307     if (it != files_in_current_dir_.end())
00308     {
00309         type_a_head_ = it - files_in_current_dir_.begin() + additional_index;
00310         move_selection(type_a_head_);
00311         return;
00312     }
00313 }
00314 
00315 void file_menu::update_file_lists() {
00316     files_in_current_dir_.clear();
00317     dirs_in_current_dir_.clear();
00318     get_files_in_dir(current_dir_, &files_in_current_dir_,
00319                      &dirs_in_current_dir_, FILE_NAME_ONLY);
00320     display_current_files();
00321 }
00322 
00323 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:58 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs