summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/gui/folder_select.c429
1 files changed, 270 insertions, 159 deletions
diff --git a/apps/gui/folder_select.c b/apps/gui/folder_select.c
index 706b166941..e324e8649a 100644
--- a/apps/gui/folder_select.c
+++ b/apps/gui/folder_select.c
@@ -8,6 +8,7 @@
8 * 8 *
9 * Copyright (C) 2012 Jonathan Gordon 9 * Copyright (C) 2012 Jonathan Gordon
10 * Copyright (C) 2012 Thomas Martitz 10 * Copyright (C) 2012 Thomas Martitz
11* * Copyright (C) 2021 William Wilgus
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 14 * modify it under the terms of the GNU General Public License
@@ -30,7 +31,11 @@
30#include "language.h" 31#include "language.h"
31#include "list.h" 32#include "list.h"
32#include "plugin.h" 33#include "plugin.h"
34#include "splash.h"
33 35
36/* Define LOGF_ENABLE to enable logf output in this file */
37//#define LOGF_ENABLE
38#include "logf.h"
34 39
35/* 40/*
36 * Order for changing child states: 41 * Order for changing child states:
@@ -56,18 +61,31 @@ struct child {
56struct folder { 61struct folder {
57 char *name; 62 char *name;
58 struct child *children; 63 struct child *children;
59 int children_count;
60 int depth;
61
62 struct folder* previous; 64 struct folder* previous;
65 uint16_t children_count;
66 uint16_t depth;
63}; 67};
64 68
65static char *buffer_front, *buffer_end; 69static char *buffer_front, *buffer_end;
70
71static struct
72{
73 int32_t len; /* keeps count versus maxlen to give buffer full notification */
74 uint32_t val; /* hash of all selected items */
75 char buf[3];/* address used as identifier -- only \0 written to it */
76 char maxlen_exceeded; /*0,1*/
77} hashed;
78
79static inline void get_hash(const char *key, uint32_t *hash, int len)
80{
81 *hash = crc_32(key, len, *hash);
82}
83
66static char* folder_alloc(size_t size) 84static char* folder_alloc(size_t size)
67{ 85{
68 char* retval; 86 char* retval;
69 /* 32-bit aligned */ 87 /* 32-bit aligned */
70 size = (size + 3) & ~3; 88 size = ALIGN_UP(size, 4);
71 if (buffer_front + size > buffer_end) 89 if (buffer_front + size > buffer_end)
72 { 90 {
73 return NULL; 91 return NULL;
@@ -86,32 +104,57 @@ static char* folder_alloc_from_end(size_t size)
86 buffer_end -= size; 104 buffer_end -= size;
87 return buffer_end; 105 return buffer_end;
88} 106}
89 107#if 0
90static void get_full_path_r(struct folder *start, char* dst) 108/* returns the buffer size required to store the path + \0 */
109static int get_full_pathsz(struct folder *start)
91{ 110{
92 if (start->previous) 111 int reql = 0;
93 get_full_path_r(start->previous, dst); 112 struct folder *next = start;
94 113 do
95 if (start->name && start->name[0] && strcmp(start->name, "/"))
96 { 114 {
97 strlcat(dst, "/", MAX_PATH); 115 reql += strlen(next->name) + 1;
98 strlcat(dst, start->name, MAX_PATH); 116 } while ((next = next->previous));
99 } 117
118 if (start->name[0] != '/') reql--;
119 if (--reql < 0) reql = 0;
120 return reql;
100} 121}
122#endif
101 123
102static char* get_full_path(struct folder *start) 124static size_t get_full_path(struct folder *start, char *dst, size_t dst_sz)
103{ 125{
104 static char buffer[MAX_PATH]; 126 size_t pos = 0;
105 127 struct folder *prev, *cur = NULL, *next = start;
106 if (strcmp(start->name, "/")) 128 dst[0] = '\0'; /* for strlcat to do its thing */
129 /* First traversal R->L mutate nodes->previous to point at child */
130 while (next->previous != NULL) /* stop at the root */
107 { 131 {
108 buffer[0] = 0; 132#define PATHMUTATE() \
109 get_full_path_r(start, buffer); 133 ({ \
134 prev = cur; \
135 cur = next; \
136 next = cur->previous;\
137 cur->previous = prev; \
138 })
139 PATHMUTATE();
110 } 140 }
111 else /* get_full_path_r() does the wrong thing for / */ 141 /*swap the next and cur nodes to reverse direction */
112 return "/"; 142 prev = next;
113 143 next = cur;
114 return buffer; 144 cur = prev;
145 /* Second traversal L->R mutate nodes->previous to point back at parent
146 * copy strings to buf as they go by */
147 while (next != NULL)
148 {
149 PATHMUTATE();
150 pos = strlcat(dst, cur->name, dst_sz);
151 /* do not append slash to paths starting with slash */
152 if (cur->name[0] != '/')
153 pos = strlcat(dst, "/", dst_sz);
154 }
155 logf("get_full_path: (%d)[%s]", (int)pos, dst);
156 return pos;
157#undef PATHMUTATE
115} 158}
116 159
117/* support function for qsort() */ 160/* support function for qsort() */
@@ -125,49 +168,52 @@ static int compare(const void* p1, const void* p2)
125static struct folder* load_folder(struct folder* parent, char *folder) 168static struct folder* load_folder(struct folder* parent, char *folder)
126{ 169{
127 DIR *dir; 170 DIR *dir;
128 char* path = get_full_path(parent);
129 char fullpath[MAX_PATH]; 171 char fullpath[MAX_PATH];
172
130 struct dirent *entry; 173 struct dirent *entry;
131 struct folder* this = (struct folder*)folder_alloc(sizeof(struct folder));
132 int child_count = 0; 174 int child_count = 0;
133 char *first_child = NULL; 175 char *first_child = NULL;
176 size_t len = 0;
134 177
135 if (!strcmp(folder,"/")) 178 struct folder* this = (struct folder*)folder_alloc(sizeof(struct folder));
136 strlcpy(fullpath, folder, 2); 179 if (this == NULL)
137 else 180 goto fail;
138 snprintf(fullpath, MAX_PATH, "%s/%s", parent ? path : "", folder); 181
182 if (parent)
183 {
184 len = get_full_path(parent, fullpath, sizeof(fullpath));
185 if (len >= sizeof(fullpath))
186 goto fail;
187 }
188 strlcpy(&fullpath[len], folder, sizeof(fullpath) - len);
189 logf("load_folder: [%s]", fullpath);
139 190
140 if (!this)
141 return NULL;
142 dir = opendir(fullpath); 191 dir = opendir(fullpath);
143 if (!dir) 192 if (dir == NULL)
144 return NULL; 193 goto fail;
145 this->previous = parent; 194 this->previous = parent;
146 this->name = folder; 195 this->name = folder;
147 this->children = NULL; 196 this->children = NULL;
148 this->children_count = 0; 197 this->children_count = 0;
149 this->depth = parent ? parent->depth + 1 : 0; 198 if (parent)
199 this->depth = parent->depth + 1;
150 200
151 while ((entry = readdir(dir))) { 201 while ((entry = readdir(dir))) {
152 int len = strlen((char *)entry->d_name);
153 struct dirinfo info;
154
155 info = dir_get_info(dir, entry);
156
157 /* skip anything not a directory */ 202 /* skip anything not a directory */
158 if ((info.attribute & ATTR_DIRECTORY) == 0) { 203 if ((dir_get_info(dir, entry).attribute & ATTR_DIRECTORY) == 0) {
159 continue; 204 continue;
160 } 205 }
161 /* skip directories . and .. */ 206 /* skip . and .. */
162 if ((!strcmp((char *)entry->d_name, ".")) || 207 char *dn = entry->d_name;
163 (!strcmp((char *)entry->d_name, ".."))) { 208 if ((dn[0] == '.') && (dn[1] == '\0' || (dn[1] == '.' && dn[2] == '\0')))
164 continue; 209 continue;
165 } 210 /* copy entry name to end of buffer, save pointer */
166 char *name = folder_alloc_from_end(len+1); 211 int len = strlen((char *)entry->d_name);
167 if (!name) 212 char *name = folder_alloc_from_end(len+1); /*for NULL*/
213 if (name == NULL)
168 { 214 {
169 closedir(dir); 215 closedir(dir);
170 return NULL; 216 goto fail;
171 } 217 }
172 memcpy(name, (char *)entry->d_name, len+1); 218 memcpy(name, (char *)entry->d_name, len+1);
173 child_count++; 219 child_count++;
@@ -177,26 +223,29 @@ static struct folder* load_folder(struct folder* parent, char *folder)
177 /* now put the names in the array */ 223 /* now put the names in the array */
178 this->children = (struct child*)folder_alloc(sizeof(struct child) * child_count); 224 this->children = (struct child*)folder_alloc(sizeof(struct child) * child_count);
179 225
180 if (!this->children) 226 if (this->children == NULL)
181 return NULL; 227 goto fail;
228
182 while (child_count) 229 while (child_count)
183 { 230 {
184 this->children[this->children_count].name = first_child; 231 struct child *child = &this->children[this->children_count++];
185 this->children[this->children_count].folder = NULL; 232 child->name = first_child;
186 this->children[this->children_count].state = COLLAPSED; 233 child->folder = NULL;
187 this->children_count++; 234 child->state = COLLAPSED;
188 first_child += strlen(first_child) + 1; 235 while(*first_child++ != '\0'){};/* move to next name entry */
189 child_count--; 236 child_count--;
190 } 237 }
191 qsort(this->children, this->children_count, sizeof(struct child), compare); 238 qsort(this->children, this->children_count, sizeof(struct child), compare);
192 239
193 return this; 240 return this;
241fail:
242 return NULL;
194} 243}
195 244
196struct folder* load_root(void) 245struct folder* load_root(void)
197{ 246{
198 static struct child root_child; 247 static struct child root_child;
199 248 /* reset the root for each call */
200 root_child.name = "/"; 249 root_child.name = "/";
201 root_child.folder = NULL; 250 root_child.folder = NULL;
202 root_child.state = COLLAPSED; 251 root_child.state = COLLAPSED;
@@ -205,7 +254,7 @@ struct folder* load_root(void)
205 .name = "", 254 .name = "",
206 .children = &root_child, 255 .children = &root_child,
207 .children_count = 1, 256 .children_count = 1,
208 .depth = -1, 257 .depth = 0,
209 .previous = NULL, 258 .previous = NULL,
210 }; 259 };
211 260
@@ -230,7 +279,6 @@ static int count_items(struct folder *start)
230static struct child* find_index(struct folder *start, int index, struct folder **parent) 279static struct child* find_index(struct folder *start, int index, struct folder **parent)
231{ 280{
232 int i = 0; 281 int i = 0;
233
234 *parent = NULL; 282 *parent = NULL;
235 283
236 while (i < start->children_count) 284 while (i < start->children_count)
@@ -262,22 +310,22 @@ static const char * folder_get_name(int selected_item, void * data,
262 struct folder *parent; 310 struct folder *parent;
263 struct child *this = find_index(root, selected_item , &parent); 311 struct child *this = find_index(root, selected_item , &parent);
264 312
265 buffer[0] = '\0'; 313 char *buf = buffer;
266 314 if ((int)buffer_len > parent->depth)
267 if (parent->depth >= 0) 315 {
268 for(int i = 0; i <= parent->depth; i++) 316 int i = parent->depth;
269 strcat(buffer, "\t"); 317 while(--i > 0) /* don't indent the parent /folders */
270 318 *buf++ = '\t';
319 }
320 *buf = '\0';
271 strlcat(buffer, this->name, buffer_len); 321 strlcat(buffer, this->name, buffer_len);
272 322
273 if (this->state == EACCESS) 323 if (this->state == EACCESS)
274 { /* append error message to the entry if unaccessible */ 324 { /* append error message to the entry if unaccessible */
275 size_t len = strlcat(buffer, " (", buffer_len); 325 size_t len = strlcat(buffer, " ( ", buffer_len);
276 if (buffer_len > len) 326 if (buffer_len > len)
277 { 327 {
278 snprintf(&buffer[len], buffer_len - len, str(LANG_READ_FAILED), 328 snprintf(&buffer[len], buffer_len - len, str(LANG_READ_FAILED), ")");
279 this->name);
280 strlcat(buffer, ")", buffer_len);
281 } 329 }
282 } 330 }
283 331
@@ -304,6 +352,23 @@ static enum themable_icons folder_get_icon(int selected_item, void * data)
304 return Icon_NOICON; 352 return Icon_NOICON;
305} 353}
306 354
355static int child_set_state_expand(struct child *this, struct folder *parent)
356{
357 int newstate = EACCESS;
358 if (this->folder == NULL)
359 this->folder = load_folder(parent, this->name);
360
361 if (this->folder != NULL)
362 {
363 if(this->folder->children_count == 0)
364 newstate = SELECTED;
365 else
366 newstate = EXPANDED;
367 }
368 this->state = newstate;
369 return newstate;
370}
371
307static int folder_action_callback(int action, struct gui_synclist *list) 372static int folder_action_callback(int action, struct gui_synclist *list)
308{ 373{
309 struct folder *root = (struct folder*)list->data; 374 struct folder *root = (struct folder*)list->data;
@@ -322,17 +387,13 @@ static int folder_action_callback(int action, struct gui_synclist *list)
322 this->state = COLLAPSED; 387 this->state = COLLAPSED;
323 break; 388 break;
324 case COLLAPSED: 389 case COLLAPSED:
325 if (this->folder == NULL) 390 child_set_state_expand(this, parent);
326 this->folder = load_folder(parent, this->name);
327 this->state = this->folder ? (this->folder->children_count == 0 ?
328 SELECTED : EXPANDED) : EACCESS;
329 break; 391 break;
330 case EACCESS: 392 case EACCESS:
331 /* cannot open, do nothing */ 393 /* cannot open, do nothing */
332 return action; 394 return action;
333 } 395 }
334 list->nb_items = count_items(root); 396 action = ACTION_REDRAW;
335 return ACTION_REDRAW;
336 } 397 }
337 else if (action == ACTION_STD_CONTEXT) 398 else if (action == ACTION_STD_CONTEXT)
338 { 399 {
@@ -342,140 +403,198 @@ static int folder_action_callback(int action, struct gui_synclist *list)
342 for (i = 0; i < this->folder->children_count; i++) 403 for (i = 0; i < this->folder->children_count; i++)
343 { 404 {
344 child = &this->folder->children[i]; 405 child = &this->folder->children[i];
345 if (child->state == SELECTED || 406 switch (child->state)
346 child->state == EXPANDED) 407 {
347 child->state = COLLAPSED; 408 case SELECTED:
348 else if (child->state == COLLAPSED) 409 case EXPANDED:
349 child->state = SELECTED; 410 child->state = COLLAPSED;
411 break;
412 case COLLAPSED:
413 child->state = SELECTED;
414 break;
415 case EACCESS:
416 break;
417 }
350 } 418 }
351 break; 419 break;
352 case SELECTED: 420 case SELECTED:
353 case COLLAPSED: 421 case COLLAPSED:
354 if (this->folder == NULL) 422 if (child_set_state_expand(this, parent) != EACCESS)
355 this->folder = load_folder(parent, this->name);
356 this->state = this->folder ? (this->folder->children_count == 0 ?
357 SELECTED : EXPANDED) : EACCESS;
358 if (this->state == EACCESS)
359 break;
360 for (i = 0; i < this->folder->children_count; i++)
361 { 423 {
362 child = &this->folder->children[i]; 424 for (i = 0; i < (this->folder->children_count); i++)
363 child->state = SELECTED; 425 {
426 child = &this->folder->children[i];
427 child->state = SELECTED;
428 }
364 } 429 }
365 break; 430 break;
366 case EACCESS: 431 case EACCESS:
367 /* cannot open, do nothing */ 432 /* cannot open, do nothing */
368 return action; 433 return action;
369 } 434 }
370 list->nb_items = count_items(root); 435 action = ACTION_REDRAW;
371 return ACTION_REDRAW;
372 } 436 }
373 437 if (action == ACTION_REDRAW)
374 438 list->nb_items = count_items(root);
375 return action; 439 return action;
376} 440}
377 441
378static struct child* find_from_filename(char* filename, struct folder *root) 442static struct child* find_from_filename(const char* filename, struct folder *root)
379{ 443{
380 char *slash = strchr(filename, '/');
381 int i = 0;
382 if (slash)
383 *slash = '\0';
384 if (!root) 444 if (!root)
385 return NULL; 445 return NULL;
386 446 const char *slash = strchr(filename, '/');
387 struct child *this; 447 struct child *this;
388 448
389 /* filenames beginning with a / are specially treated as the 449 /* filenames beginning with a / are specially treated as the
390 * loop below can't handle them. they can only occur on the first, 450 * loop below can't handle them. they can only occur on the first,
391 * and not recursive, calls to this function.*/ 451 * and not recursive, calls to this function.*/
392 if (slash == filename) 452 if (filename[0] == '/') /* in the loop nothing starts with '/' */
393 { 453 {
454 logf("find_from_filename [%s]", filename);
394 /* filename begins with /. in this case root must be the 455 /* filename begins with /. in this case root must be the
395 * top level folder */ 456 * top level folder */
396 this = &root->children[0]; 457 this = &root->children[0];
397 if (!slash[1]) 458 if (filename[1] == '\0')
398 { /* filename == "/" */ 459 { /* filename == "/" */
399 return this; 460 return this;
400 } 461 }
401 else 462 else /* filename == "/XXX/YYY". cascade down */
402 { 463 goto cascade;
403 /* filename == "/XXX/YYY". cascade down */
404 if (!this->folder)
405 this->folder = load_folder(root, this->name);
406 this->state = EXPANDED;
407 /* recurse with XXX/YYY */
408 return find_from_filename(slash+1, this->folder);
409 }
410 } 464 }
411 465
412 while (i < root->children_count) 466 for (int i = 0; i < root->children_count; i++)
413 { 467 {
414 this = &root->children[i]; 468 this = &root->children[i];
415 if (!strcasecmp(this->name, filename)) 469 /* when slash == NULL n will be really large but \0 stops the compare */
470 if (strncasecmp(this->name, filename, slash - filename) == 0)
416 { 471 {
417 if (!slash) 472 if (slash == NULL)
418 { /* filename == XXX */ 473 { /* filename == XXX */
419 return this; 474 return this;
420 } 475 }
421 else 476 else
422 { 477 goto cascade;
423 /* filename == XXX/YYY. cascade down */
424 if (!this->folder)
425 this->folder = load_folder(root, this->name);
426 this->state = EXPANDED;
427 return find_from_filename(slash+1, this->folder);
428 }
429 } 478 }
430 i++;
431 } 479 }
432 return NULL; 480 return NULL;
481
482cascade:
483 /* filename == XXX/YYY. cascade down */
484 child_set_state_expand(this, root);
485 while (slash[0] == '/') slash++; /* eat slashes */
486 return find_from_filename(slash, this->folder);
433} 487}
434 488
435/* _modifies_ buf */ 489static int select_paths(struct folder* root, const char* filenames)
436int select_paths(struct folder* root, char* buf)
437{ 490{
438 struct child *item = find_from_filename(buf, root); 491 /* Takes a list of filenames in a ':' delimited string
439 if (item) 492 splits filenames at the ':' character loads each into buffer
440 item->state = SELECTED; 493 selects each file in the folder list
494
495 if last item or only item the rest of the string is copied to the buffer
496 *End the last item WITHOUT the ':' character /.rockbox/eqs:/.rockbox/wps\0*
497 */
498 char buf[MAX_PATH];
499 const int buflen = sizeof(buf);
500
501 const char *fnp = filenames;
502 const char *lastfnp = fnp;
503 const char *sstr;
504 off_t len;
505
506 while (fnp)
507 {
508 fnp = strchr(fnp, ':');
509 if (fnp)
510 {
511 len = fnp - lastfnp;
512 fnp++;
513 }
514 else /* no ':' get the rest of the string */
515 len = strlen(lastfnp);
516
517 sstr = lastfnp;
518 lastfnp = fnp;
519 if (len <= 0 || len > buflen)
520 continue;
521 strlcpy(buf, sstr, len + 1);
522 struct child *item = find_from_filename(buf, root);
523 if (item)
524 item->state = SELECTED;
525 }
526
441 return 0; 527 return 0;
442} 528}
443 529
444static void save_folders_r(struct folder *root, char* dst, size_t maxlen) 530static void save_folders_r(struct folder *root, char* dst, size_t maxlen, size_t buflen)
445{ 531{
446 int i = 0; 532 size_t len;
533 struct folder *curfolder;
534 char* name;
447 535
448 while (i < root->children_count) 536 for (int i = 0; i < root->children_count; i++)
449 { 537 {
450 struct child *this = &root->children[i]; 538 struct child *this = &root->children[i];
451 if (this->state == SELECTED) 539 if (this->state == SELECTED)
452 { 540 {
453 if (this->folder) 541 if (this->folder == NULL)
454 snprintf(buffer_front, buffer_end - buffer_front, 542 {
455 "%s:", get_full_path(this->folder)); 543 curfolder = root;
544 name = this->name;
545 logf("save_folders_r: this->name[%s]", name);
546 }
547 else
548 {
549 curfolder = this->folder->previous;
550 name = this->folder->name;
551 logf("save_folders_r: this->folder->name[%s]", name);
552 }
553
554 len = get_full_path(curfolder, buffer_front, buflen);
555
556 if (len + 2 >= buflen)
557 continue;
558
559 len += snprintf(&buffer_front[len], buflen - len, "%s:", name);
560 logf("save_folders_r: [%s]", buffer_front);
561 if (dst != hashed.buf)
562 {
563 int dlen = strlen(dst);
564 if (dlen + len >= maxlen)
565 continue;
566 strlcpy(&dst[dlen], buffer_front, maxlen - dlen);
567 }
456 else 568 else
457 { 569 {
458 char *p = get_full_path(root); 570 if (hashed.len + len >= maxlen)
459 snprintf(buffer_front, buffer_end - buffer_front, 571 {
460 "%s/%s:", strcmp(p, "/") ? p : "", 572 hashed.maxlen_exceeded = 1;
461 strcmp(this->name, "/") ? this->name : ""); 573 continue;
574 }
575 get_hash(buffer_front, &hashed.val, len);
576 hashed.len += len;
462 } 577 }
463 strlcat(dst, buffer_front, maxlen);
464 } 578 }
465 else if (this->state == EXPANDED) 579 else if (this->state == EXPANDED)
466 save_folders_r(this->folder, dst, maxlen); 580 save_folders_r(this->folder, dst, maxlen, buflen);
467 i++;
468 } 581 }
469} 582}
470 583
471static void save_folders(struct folder *root, char* dst, size_t maxlen) 584static uint32_t save_folders(struct folder *root, char* dst, size_t maxlen)
472{ 585{
473 int len; 586 hashed.len = 0;
587 hashed.val = 0;
588 hashed.maxlen_exceeded = 0;
589 size_t len = buffer_end - buffer_front;
474 dst[0] = '\0'; 590 dst[0] = '\0';
475 save_folders_r(root, dst, maxlen); 591 save_folders_r(root, dst, maxlen, len);
476 len = strlen(dst); 592 len = strlen(dst);
477 /* fix trailing ':' */ 593 /* fix trailing ':' */
478 if (len > 1) dst[len-1] = '\0'; 594 if (len > 1) dst[len-1] = '\0';
595 /*Notify - user will probably not see save dialog if nothing new got added*/
596 if (hashed.maxlen_exceeded > 0) splash(HZ *2, ID2P(LANG_SHOWDIR_BUFFER_FULL));
597 return hashed.val;
479} 598}
480 599
481bool folder_select(char* setting, int setting_len) 600bool folder_select(char* setting, int setting_len)
@@ -483,40 +602,32 @@ bool folder_select(char* setting, int setting_len)
483 struct folder *root; 602 struct folder *root;
484 struct simplelist_info info; 603 struct simplelist_info info;
485 size_t buf_size; 604 size_t buf_size;
486 /* 32 separate folders should be Enough For Everybody(TM) */
487 char *vect[32];
488 char copy[setting_len];
489 int nb_items;
490
491 /* copy onto stack as split_string() modifies it */
492 strlcpy(copy, setting, setting_len);
493 nb_items = split_string(copy, ':', vect, ARRAYLEN(vect));
494 605
495 buffer_front = plugin_get_buffer(&buf_size); 606 buffer_front = plugin_get_buffer(&buf_size);
496 buffer_end = buffer_front + buf_size; 607 buffer_end = buffer_front + buf_size;
608 logf("%d bytes free", (int)(buffer_end - buffer_front));
497 root = load_root(); 609 root = load_root();
498 610
499 if (nb_items > 0) 611 logf("folders in: %s", setting);
500 { 612 /* Load previous selection(s) */
501 for(int i = 0; i < nb_items; i++) 613 select_paths(root, setting);
502 select_paths(root, vect[i]); 614 /* get current hash to check for changes later */
503 } 615 uint32_t hash = save_folders(root, hashed.buf, setting_len);
504
505 simplelist_info_init(&info, str(LANG_SELECT_FOLDER), 616 simplelist_info_init(&info, str(LANG_SELECT_FOLDER),
506 count_items(root), root); 617 count_items(root), root);
507 info.get_name = folder_get_name; 618 info.get_name = folder_get_name;
508 info.action_callback = folder_action_callback; 619 info.action_callback = folder_action_callback;
509 info.get_icon = folder_get_icon; 620 info.get_icon = folder_get_icon;
510 simplelist_show_list(&info); 621 simplelist_show_list(&info);
511 622 logf("%d bytes free", (int)(buffer_end - buffer_front));
512 /* done editing. check for changes */ 623 /* done editing. check for changes */
513 save_folders(root, copy, setting_len); 624 if (hash != save_folders(root, hashed.buf, setting_len))
514 if (strcmp(copy, setting)) 625 { /* prompt for saving changes and commit if yes */
515 { /* prompt for saving changes and commit if yes */
516 if (yesno_pop(ID2P(LANG_SAVE_CHANGES))) 626 if (yesno_pop(ID2P(LANG_SAVE_CHANGES)))
517 { 627 {
518 strcpy(setting, copy); 628 save_folders(root, setting, setting_len);
519 settings_save(); 629 settings_save();
630 logf("folders out: %s", setting);
520 return true; 631 return true;
521 } 632 }
522 } 633 }