1// SuperTux
2// Copyright (C) 2016 Hume2 <teratux.mail@gmail.com>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "gui/menu_filesystem.hpp"
18
19#include <physfs.h>
20
21#include "addon/addon_manager.hpp"
22#include "gui/menu_item.hpp"
23#include "gui/menu_manager.hpp"
24#include "physfs/util.hpp"
25#include "util/file_system.hpp"
26#include "util/log.hpp"
27#include "util/gettext.hpp"
28#include "util/string_util.hpp"
29
30FileSystemMenu::FileSystemMenu(std::string* filename, const std::vector<std::string>& extensions,
31 const std::string& basedir) :
32 m_filename(filename),
33 // when a basedir is given, 'filename' is relative to basedir, so
34 // it's useless as a starting point
35 m_directory(basedir.empty() ? FileSystem::dirname(*filename) : basedir),
36 m_extensions(extensions),
37 m_basedir(basedir),
38 m_directories(),
39 m_files()
40{
41 AddonManager::current()->unmount_old_addons();
42
43 if (!PHYSFS_exists(m_directory.c_str())) {
44 m_directory = "/"; //The filename is probably included in an old add-on.
45 }
46
47 refresh_items();
48}
49
50FileSystemMenu::~FileSystemMenu()
51{
52 AddonManager::current()->mount_old_addons();
53}
54
55void
56FileSystemMenu::refresh_items()
57{
58 m_items.clear();
59 m_directories.clear();
60 m_files.clear();
61 m_directory = FileSystem::normalize(m_directory);
62
63 add_label(m_directory);
64 add_hl();
65
66 int item_id = 0;
67
68 // Do not allow leaving the data directory
69 if (m_directory != "/") {
70 m_directories.push_back("..");
71 }
72
73 char** dir_files = PHYSFS_enumerateFiles(m_directory.c_str());
74 if (dir_files)
75 {
76 for (const char* const* file = dir_files; *file != nullptr; ++file)
77 {
78 std::string filepath = FileSystem::join(m_directory, *file);
79 if (physfsutil::is_directory(filepath))
80 {
81 m_directories.push_back(*file);
82 }
83 else
84 {
85 if (AddonManager::current()->is_from_old_addon(filepath)) {
86 continue;
87 }
88
89 if (has_right_suffix(*file))
90 {
91 m_files.push_back(*file);
92 }
93 }
94 }
95 PHYSFS_freeList(dir_files);
96 }
97
98 for (const auto& item : m_directories)
99 {
100 add_entry(item_id, "[" + std::string(item) + "]");
101 item_id++;
102 }
103
104 for (const auto& item : m_files)
105 {
106 add_entry(item_id, item);
107 item_id++;
108 }
109
110 add_hl();
111 add_back(_("Cancel"));
112
113 m_active_item = 2;
114
115 // Re-center menu
116 on_window_resize();
117}
118
119bool
120FileSystemMenu::has_right_suffix(const std::string& file) const
121{
122 for (const auto& extension : m_extensions) {
123 if (StringUtil::has_suffix(file, extension))
124 {
125 return true;
126 }
127 }
128 return false;
129}
130
131void
132FileSystemMenu::menu_action(MenuItem& item)
133{
134 if (item.get_id() >= 0) {
135 size_t id = item.get_id();
136 if (id < m_directories.size()) {
137 m_directory = FileSystem::join(m_directory, m_directories[id]);
138 refresh_items();
139 } else {
140 id -= m_directories.size();
141 if (id < m_files.size()) {
142 std::string new_filename = FileSystem::join(m_directory, m_files[id]);
143
144 if (!m_basedir.empty()) {
145 new_filename = FileSystem::relpath(new_filename, m_basedir);
146 }
147
148 *m_filename = new_filename;
149
150 MenuManager::instance().pop_menu();
151 } else {
152 log_warning << "Selected invalid file or directory" << std::endl;
153 }
154 }
155 }
156}
157
158/* EOF */
159