blob: fe378c8482db5743c9c184996614cc68ce5014c8 [file] [log] [blame]
Dees_Troya13d74f2013-03-24 08:54:55 -05001/*
2 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP 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 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
Dees_Troy51a0e822012-09-05 15:24:24 -040018
Dees_Troy51a0e822012-09-05 15:24:24 -040019#include <string.h>
Dees_Troy51a0e822012-09-05 15:24:24 -040020#include <sys/stat.h>
Dees_Troy51a0e822012-09-05 15:24:24 -040021#include <dirent.h>
Dees_Troy51a0e822012-09-05 15:24:24 -040022#include <algorithm>
23
24extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000025#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040026}
Ethan Yonkerfbb43532015-12-28 21:54:50 +010027#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040028
29#include "rapidxml.hpp"
30#include "objects.hpp"
31#include "../data.hpp"
Dees_Troy3ee47bc2013-01-25 21:47:37 +000032#include "../twrp-functions.hpp"
bigbiff bigbiff19fb79c2016-09-05 21:04:51 -040033#include "../adbbu/libtwadbbu.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040034
Dees_Troy51a0e822012-09-05 15:24:24 -040035int GUIFileSelector::mSortOrder = 0;
36
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010037GUIFileSelector::GUIFileSelector(xml_node<>* node) : GUIScrollList(node)
Dees_Troy51a0e822012-09-05 15:24:24 -040038{
39 xml_attribute<>* attr;
40 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -040041
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010042 mFolderIcon = mFileIcon = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -040043 mShowFolders = mShowFiles = mShowNavFolders = 1;
44 mUpdate = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -040045 mPathVar = "cwd";
Dees_Troyc0583f52013-02-28 11:19:57 -060046 updateFileList = false;
Dees_Troy51a0e822012-09-05 15:24:24 -040047
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010048 // Load filter for filtering files (e.g. *.zip for only zips)
that72b90e32015-02-23 22:57:14 +010049 child = FindNode(node, "filter");
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010050 if (child) {
Dees_Troy51a0e822012-09-05 15:24:24 -040051 attr = child->first_attribute("extn");
52 if (attr)
53 mExtn = attr->value();
54 attr = child->first_attribute("folders");
55 if (attr)
56 mShowFolders = atoi(attr->value());
57 attr = child->first_attribute("files");
58 if (attr)
59 mShowFiles = atoi(attr->value());
60 attr = child->first_attribute("nav");
61 if (attr)
62 mShowNavFolders = atoi(attr->value());
63 }
64
65 // Handle the path variable
that72b90e32015-02-23 22:57:14 +010066 child = FindNode(node, "path");
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010067 if (child) {
Dees_Troy51a0e822012-09-05 15:24:24 -040068 attr = child->first_attribute("name");
69 if (attr)
70 mPathVar = attr->value();
71 attr = child->first_attribute("default");
Ethan Yonker21ff02a2015-02-18 14:35:00 -060072 if (attr) {
73 mPathDefault = attr->value();
Dees_Troy51a0e822012-09-05 15:24:24 -040074 DataManager::SetValue(mPathVar, attr->value());
Ethan Yonker21ff02a2015-02-18 14:35:00 -060075 }
Dees_Troy51a0e822012-09-05 15:24:24 -040076 }
77
78 // Handle the result variable
that72b90e32015-02-23 22:57:14 +010079 child = FindNode(node, "data");
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010080 if (child) {
Dees_Troy51a0e822012-09-05 15:24:24 -040081 attr = child->first_attribute("name");
82 if (attr)
83 mVariable = attr->value();
84 attr = child->first_attribute("default");
85 if (attr)
86 DataManager::SetValue(mVariable, attr->value());
87 }
88
89 // Handle the sort variable
that72b90e32015-02-23 22:57:14 +010090 child = FindNode(node, "sort");
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010091 if (child) {
Dees_Troy51a0e822012-09-05 15:24:24 -040092 attr = child->first_attribute("name");
93 if (attr)
94 mSortVariable = attr->value();
95 attr = child->first_attribute("default");
96 if (attr)
97 DataManager::SetValue(mSortVariable, attr->value());
98
99 DataManager::GetValue(mSortVariable, mSortOrder);
100 }
101
102 // Handle the selection variable
that72b90e32015-02-23 22:57:14 +0100103 child = FindNode(node, "selection");
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100104 if (child && (attr = child->first_attribute("name")))
105 mSelection = attr->value();
106 else
Dees_Troy51a0e822012-09-05 15:24:24 -0400107 mSelection = "0";
108
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100109 // Get folder and file icons if present
that72b90e32015-02-23 22:57:14 +0100110 child = FindNode(node, "icon");
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100111 if (child) {
thatf6ed8fc2015-02-14 20:23:16 +0100112 mFolderIcon = LoadAttrImage(child, "folder");
113 mFileIcon = LoadAttrImage(child, "file");
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100114 }
Ethan Yonker58f21322018-08-24 11:17:36 -0500115 int iconWidth = 0, iconHeight = 0;
116 if (mFolderIcon && mFolderIcon->GetResource() && mFileIcon && mFileIcon->GetResource()) {
117 iconWidth = std::max(mFolderIcon->GetWidth(), mFileIcon->GetWidth());
118 iconHeight = std::max(mFolderIcon->GetHeight(), mFileIcon->GetHeight());
119 } else if (mFolderIcon && mFolderIcon->GetResource()) {
120 iconWidth = mFolderIcon->GetWidth();
121 iconHeight = mFolderIcon->GetHeight();
122 } else if (mFileIcon && mFileIcon->GetResource()) {
123 iconWidth = mFileIcon->GetWidth();
124 iconHeight = mFileIcon->GetHeight();
125 }
thatf6ed8fc2015-02-14 20:23:16 +0100126 SetMaxIconSize(iconWidth, iconHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400127
128 // Fetch the file/folder list
129 std::string value;
130 DataManager::GetValue(mPathVar, value);
Dees_Troy80a11d92013-01-25 16:36:07 +0000131 GetFileList(value);
Dees_Troy51a0e822012-09-05 15:24:24 -0400132}
133
134GUIFileSelector::~GUIFileSelector()
135{
Dees_Troy51a0e822012-09-05 15:24:24 -0400136}
137
138int GUIFileSelector::Update(void)
139{
Matt Mowera8a89d12016-12-30 18:10:37 -0600140 if (!isConditionTrue())
Vojtech Bocekede51c52014-02-07 23:58:09 +0100141 return 0;
142
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100143 GUIScrollList::Update();
144
145 // Update the file list if needed
146 if (updateFileList) {
147 string value;
148 DataManager::GetValue(mPathVar, value);
149 if (GetFileList(value) == 0) {
150 updateFileList = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400151 mUpdate = 1;
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100152 } else
153 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400154 }
155
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100156 if (mUpdate) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400157 mUpdate = 0;
158 if (Render() == 0)
159 return 2;
160 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400161 return 0;
162}
163
Vojtech Bocek07220562014-02-08 02:05:33 +0100164int GUIFileSelector::NotifyVarChange(const std::string& varName, const std::string& value)
Dees_Troy51a0e822012-09-05 15:24:24 -0400165{
thatfa30aca2015-02-13 01:22:22 +0100166 GUIScrollList::NotifyVarChange(varName, value);
167
Matt Mowera8a89d12016-12-30 18:10:37 -0600168 if (!isConditionTrue())
Vojtech Bocekede51c52014-02-07 23:58:09 +0100169 return 0;
170
Dees_Troy146d72a2013-03-11 17:46:19 +0000171 if (varName.empty()) {
172 // Always clear the data variable so we know to use it
173 DataManager::SetValue(mVariable, "");
174 }
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100175 if (varName == mPathVar || varName == mSortVariable) {
Dees_Troy4622cf92013-03-01 15:29:36 -0600176 if (varName == mSortVariable) {
177 DataManager::GetValue(mSortVariable, mSortOrder);
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100178 } else {
179 // Reset the list to the top
180 SetVisibleListLocation(0);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600181 if (value.empty())
182 DataManager::SetValue(mPathVar, mPathDefault);
Dees_Troyc0583f52013-02-28 11:19:57 -0600183 }
184 updateFileList = true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400185 mUpdate = 1;
186 return 0;
187 }
188 return 0;
189}
190
Dees_Troy51a0e822012-09-05 15:24:24 -0400191bool GUIFileSelector::fileSort(FileData d1, FileData d2)
192{
193 if (d1.fileName == ".")
194 return -1;
195 if (d2.fileName == ".")
196 return 0;
thatc12a7f02016-01-28 20:52:16 +0100197 if (d1.fileName == "..")
Dees_Troy51a0e822012-09-05 15:24:24 -0400198 return -1;
thatc12a7f02016-01-28 20:52:16 +0100199 if (d2.fileName == "..")
Dees_Troy51a0e822012-09-05 15:24:24 -0400200 return 0;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500201
Dees_Troy51a0e822012-09-05 15:24:24 -0400202 switch (mSortOrder) {
203 case 3: // by size largest first
204 if (d1.fileSize == d2.fileSize || d1.fileType == DT_DIR) // some directories report a different size than others - but this is not the size of the files inside the directory, so we just sort by name on directories
205 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600206 return d1.fileSize < d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400207 case -3: // by size smallest first
208 if (d1.fileSize == d2.fileSize || d1.fileType == DT_DIR) // some directories report a different size than others - but this is not the size of the files inside the directory, so we just sort by name on directories
209 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600210 return d1.fileSize > d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400211 case 2: // by last modified date newest first
212 if (d1.lastModified == d2.lastModified)
213 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600214 return d1.lastModified < d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400215 case -2: // by date oldest first
216 if (d1.lastModified == d2.lastModified)
217 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600218 return d1.lastModified > d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400219 case -1: // by name descending
220 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
221 default: // should be a 1 - sort by name ascending
222 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
223 }
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100224 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400225}
226
227int GUIFileSelector::GetFileList(const std::string folder)
228{
229 DIR* d;
230 struct dirent* de;
231 struct stat st;
232
233 // Clear all data
234 mFolderList.clear();
235 mFileList.clear();
236
237 d = opendir(folder.c_str());
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100238 if (d == NULL) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000239 LOGINFO("Unable to open '%s'\n", folder.c_str());
Dees_Troy80a11d92013-01-25 16:36:07 +0000240 if (folder != "/" && (mShowNavFolders != 0 || mShowFiles != 0)) {
241 size_t found;
242 found = folder.find_last_of('/');
243 if (found != string::npos) {
244 string new_folder = folder.substr(0, found);
245
246 if (new_folder.length() < 2)
247 new_folder = "/";
248 DataManager::SetValue(mPathVar, new_folder);
249 }
250 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400251 return -1;
252 }
253
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100254 while ((de = readdir(d)) != NULL) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400255 FileData data;
256
257 data.fileName = de->d_name;
258 if (data.fileName == ".")
259 continue;
260 if (data.fileName == ".." && folder == "/")
261 continue;
thatc12a7f02016-01-28 20:52:16 +0100262
263 data.fileType = de->d_type;
Dees_Troy51a0e822012-09-05 15:24:24 -0400264
265 std::string path = folder + "/" + data.fileName;
266 stat(path.c_str(), &st);
267 data.protection = st.st_mode;
268 data.userId = st.st_uid;
269 data.groupId = st.st_gid;
270 data.fileSize = st.st_size;
271 data.lastAccess = st.st_atime;
272 data.lastModified = st.st_mtime;
273 data.lastStatChange = st.st_ctime;
274
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000275 if (data.fileType == DT_UNKNOWN) {
276 data.fileType = TWFunc::Get_D_Type_From_Stat(path);
277 }
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100278 if (data.fileType == DT_DIR) {
thatc12a7f02016-01-28 20:52:16 +0100279 if (mShowNavFolders || (data.fileName != "." && data.fileName != ".."))
Dees_Troy51a0e822012-09-05 15:24:24 -0400280 mFolderList.push_back(data);
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100281 } else if (data.fileType == DT_REG || data.fileType == DT_LNK || data.fileType == DT_BLK) {
282 if (mExtn.empty() || (data.fileName.length() > mExtn.length() && data.fileName.substr(data.fileName.length() - mExtn.length()) == mExtn)) {
bigbiff bigbiff19fb79c2016-09-05 21:04:51 -0400283 if (mExtn == ".ab" && twadbbu::Check_ADB_Backup_File(path))
284 mFolderList.push_back(data);
285 else
286 mFileList.push_back(data);
Dees_Troy51a0e822012-09-05 15:24:24 -0400287 }
288 }
289 }
290 closedir(d);
291
292 std::sort(mFolderList.begin(), mFolderList.end(), fileSort);
293 std::sort(mFileList.begin(), mFileList.end(), fileSort);
Dees_Troyc0583f52013-02-28 11:19:57 -0600294
Dees_Troy51a0e822012-09-05 15:24:24 -0400295 return 0;
296}
297
298void GUIFileSelector::SetPageFocus(int inFocus)
299{
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100300 GUIScrollList::SetPageFocus(inFocus);
301 if (inFocus) {
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600302 std::string value;
303 DataManager::GetValue(mPathVar, value);
304 if (value.empty())
305 DataManager::SetValue(mPathVar, mPathDefault);
Dees_Troyc0583f52013-02-28 11:19:57 -0600306 updateFileList = true;
Dees_Troyc0583f52013-02-28 11:19:57 -0600307 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400308 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500309}
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100310
311size_t GUIFileSelector::GetItemCount()
312{
313 size_t folderSize = mShowFolders ? mFolderList.size() : 0;
314 size_t fileSize = mShowFiles ? mFileList.size() : 0;
315 return folderSize + fileSize;
316}
317
that0af77952015-02-25 08:52:19 +0100318void GUIFileSelector::RenderItem(size_t itemindex, int yPos, bool selected)
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100319{
320 size_t folderSize = mShowFolders ? mFolderList.size() : 0;
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100321
that0af77952015-02-25 08:52:19 +0100322 ImageResource* icon;
323 std::string text;
324
325 if (itemindex < folderSize) {
326 text = mFolderList.at(itemindex).fileName;
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100327 icon = mFolderIcon;
thatc12a7f02016-01-28 20:52:16 +0100328 if (text == "..")
329 text = gui_lookup("up_a_level", "(Up A Level)");
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100330 } else {
that0af77952015-02-25 08:52:19 +0100331 text = mFileList.at(itemindex - folderSize).fileName;
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100332 icon = mFileIcon;
333 }
that0af77952015-02-25 08:52:19 +0100334
335 RenderStdItem(yPos, selected, icon, text.c_str());
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100336}
337
338void GUIFileSelector::NotifySelect(size_t item_selected)
339{
340 size_t folderSize = mShowFolders ? mFolderList.size() : 0;
341 size_t fileSize = mShowFiles ? mFileList.size() : 0;
342
343 if (item_selected < folderSize + fileSize) {
344 // We've selected an item!
345 std::string str;
346 if (item_selected < folderSize) {
347 std::string cwd;
348
349 str = mFolderList.at(item_selected).fileName;
350 if (mSelection != "0")
351 DataManager::SetValue(mSelection, str);
352 DataManager::GetValue(mPathVar, cwd);
353
354 // Ignore requests to do nothing
355 if (str == ".") return;
thatc12a7f02016-01-28 20:52:16 +0100356 if (str == "..") {
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100357 if (cwd != "/") {
358 size_t found;
359 found = cwd.find_last_of('/');
360 cwd = cwd.substr(0,found);
361
362 if (cwd.length() < 2) cwd = "/";
363 }
364 } else {
365 // Add a slash if we're not the root folder
366 if (cwd != "/") cwd += "/";
367 cwd += str;
368 }
369
bigbiff bigbiff19fb79c2016-09-05 21:04:51 -0400370 if (mShowNavFolders == 0 && (mShowFiles == 0 || mExtn == ".ab")) {
371 // this is probably the restore list and we need to save chosen location to mVariable instead of mPathVar
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100372 DataManager::SetValue(mVariable, cwd);
373 } else {
374 // We are changing paths, so we need to set mPathVar
375 DataManager::SetValue(mPathVar, cwd);
376 }
377 } else if (!mVariable.empty()) {
378 str = mFileList.at(item_selected - folderSize).fileName;
379 if (mSelection != "0")
380 DataManager::SetValue(mSelection, str);
381
382 std::string cwd;
383 DataManager::GetValue(mPathVar, cwd);
384 if (cwd != "/")
385 cwd += "/";
386 DataManager::SetValue(mVariable, cwd + str);
387 }
388 }
389 mUpdate = 1;
390}