blob: e6b89b76418c82ca375d06f9ffbcc13dd9808382 [file] [log] [blame]
Peter D'Hoye946a8152007-09-03 22:24:26 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Bryan Childs
11 * Copyright (c) 2007 Alexander Levin
12 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000013 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
Peter D'Hoye946a8152007-09-03 22:24:26 +000017 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#include "shortcuts.h"
24
25PLUGIN_HEADER
26
27enum sc_list_action_type
28{
29 SCLA_NONE,
30 SCLA_SELECT,
31 SCLA_DELETE,
32 SCLA_USB,
33};
34
35
36static char *link_filename;
37static bool user_file;
38static int gselected_item;
39static bool usb_connected = false;
40
41enum sc_list_action_type draw_sc_list(struct gui_synclist gui_sc);
42
43/* Will be passed sc_file* as data */
Nils Wallménius68489612008-04-09 15:25:17 +000044char* build_sc_list(int selected_item, void *data,
45 char *buffer, size_t buffer_len);
Peter D'Hoye946a8152007-09-03 22:24:26 +000046
47/* Returns true iff we should leave the main loop */
48bool list_sc(bool is_editable);
49
50bool goto_entry(char *file_or_dir);
51bool ends_with(char *str, char *suffix);
52
53
54enum sc_list_action_type draw_sc_list(struct gui_synclist gui_sc)
55{
56 int button;
57
58 rb->gui_synclist_draw(&gui_sc);
59
60 while (true) {
61 /* draw the statusbar, should be done often */
62 rb->gui_syncstatusbar_draw(rb->statusbars, true);
63 /* user input */
64 button = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK);
Jonathan Gordoncf1cef52007-09-17 10:08:50 +000065 if (rb->gui_synclist_do_button(&gui_sc, &button,
Peter D'Hoye946a8152007-09-03 22:24:26 +000066 LIST_WRAP_UNLESS_HELD)) {
67 /* automatic handling of user input.
68 * _UNLESS_HELD can be _ON or _OFF also
69 * selection changed, so redraw */
70 continue;
71 }
72 switch (button) { /* process the user input */
73 case ACTION_STD_OK:
74 gselected_item = rb->gui_synclist_get_sel_pos(&gui_sc);
75 return SCLA_SELECT;
76 case ACTION_STD_MENU:
77 /* Only allow delete entries in the default file
78 * since entries can be appended (with a plugin)
79 * to the default file only. The behaviour is thus
80 * symmetric in this respect. */
81 if (!user_file) {
82 gselected_item = rb->gui_synclist_get_sel_pos(&gui_sc);
83 return SCLA_DELETE;
84 }
85 break;
86 case ACTION_STD_CANCEL:
87 return SCLA_NONE;
88 default:
89 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
90 return SCLA_USB;
91 }
92 }
93 }
94}
95
96
Nils Wallménius68489612008-04-09 15:25:17 +000097char* build_sc_list(int selected_item, void *data,
98 char *buffer, size_t buffer_len)
Peter D'Hoye946a8152007-09-03 22:24:26 +000099{
Peter D'Hoye946a8152007-09-03 22:24:26 +0000100 sc_file_t *file = (sc_file_t*)data;
101
102 if (!is_valid_index(file, selected_item)) {
103 return NULL;
104 }
105 sc_entry_t *entry = file->entries + selected_item;
Nils Wallménius68489612008-04-09 15:25:17 +0000106 rb->snprintf(buffer, buffer_len, "%s", entry->disp);
Peter D'Hoye946a8152007-09-03 22:24:26 +0000107 return buffer;
108}
109
110
111bool list_sc(bool is_editable)
112{
113 int selected_item = 0;
114 char selected_dir[MAX_PATH];
115 enum sc_list_action_type action = SCLA_NONE;
116 struct gui_synclist gui_sc;
117
118 rb->memset(selected_dir, 0, sizeof(selected_dir));
119
120 /* Setup the GUI list object, draw it to the screen,
121 * and then handle the user input to it */
Jonathan Gordon5ca15392008-03-26 03:35:24 +0000122 rb->gui_synclist_init(&gui_sc, &build_sc_list, &sc_file, false, 1, NULL);
Peter D'Hoye946a8152007-09-03 22:24:26 +0000123 rb->gui_synclist_set_title(&gui_sc,
124 (is_editable?"Shortcuts (editable)":"Shortcuts (sealed)"), NOICON);
125 rb->gui_synclist_set_nb_items(&gui_sc, sc_file.entry_cnt);
126 rb->gui_synclist_limit_scroll(&gui_sc, false);
127 rb->gui_synclist_select_item(&gui_sc, 0);
128
129 /* Draw the prepared widget to the LCD now */
130 action = draw_sc_list(gui_sc);
131 if (action == SCLA_USB) {
132 usb_connected = true;
133 return true;
134 }
135
136 /* which item do we action? */
137 selected_item = gselected_item;
138
139 if (!is_valid_index(&sc_file, selected_item)) {
140 /* This should never happen */
141 rb->splash(HZ*2, "Bad entry selected!");
142 return true;
143 }
144
145 /* perform the following actions if the user "selected"
146 * the item in the list (i.e. they want to go there
147 * in the filebrowser tree */
148 switch(action) {
149 case SCLA_SELECT:
150 return goto_entry(sc_file.entries[selected_item].path);
151 case SCLA_DELETE:
152 rb->splash(HZ, "Deleting %s", sc_file.entries[selected_item].disp);
153 remove_entry(&sc_file, selected_item);
154 dump_sc_file(&sc_file, link_filename);
155 return (sc_file.entry_cnt == 0);
156 default:
157 return true;
158 }
159}
160
161
162bool goto_entry(char *file_or_dir)
163{
164 DEBUGF("Trying to go to '%s'...\n", file_or_dir);
165
166 bool is_dir = ends_with(file_or_dir, PATH_SEPARATOR);
167 bool exists;
168 char *what;
169 if (is_dir) {
170 what = "Directory";
Robert Kuklad87b0372007-11-21 21:28:27 +0000171 exists = rb->dir_exists(file_or_dir);
Peter D'Hoye946a8152007-09-03 22:24:26 +0000172 } else {
173 what = "File";
Robert Kuklad87b0372007-11-21 21:28:27 +0000174 exists = rb->file_exists(file_or_dir);
Peter D'Hoye946a8152007-09-03 22:24:26 +0000175 }
176
177 if (!exists) {
178 rb->splash(HZ*2, "%s %s no longer exists on disk", what, file_or_dir);
179 return false;
180 }
181 /* Set the browsers dirfilter to the global setting
182 * This is required in case the plugin was launched
183 * from the plugins browser, in which case the
184 * dirfilter is set to only display .rock files */
185 rb->set_dirfilter(rb->global_settings->dirfilter);
186
187 /* Change directory to the entry selected by the user */
188 rb->set_current_file(file_or_dir);
189 return true;
190}
191
192
193bool ends_with(char *string, char *suffix)
194{
195 unsigned int str_len = rb->strlen(string);
196 unsigned int sfx_len = rb->strlen(suffix);
197 if (str_len < sfx_len)
198 return false;
199 return (rb->strncmp(string + str_len - sfx_len, suffix, sfx_len) == 0);
200}
201
202
Steve Bavin65265772008-05-13 09:57:56 +0000203enum plugin_status plugin_start(const struct plugin_api* api, const void* void_parameter)
Peter D'Hoye946a8152007-09-03 22:24:26 +0000204{
205 rb = api;
206 bool leave_loop;
207
208 /* This is a viewer, so a parameter must have been specified */
209 if (void_parameter == NULL) {
210 rb->splash(HZ*2, "No parameter specified!");
211 return PLUGIN_ERROR;
212 }
213 link_filename = (char*)void_parameter;
214 user_file = (rb->strcmp(link_filename, SHORTCUTS_FILENAME) != 0);
215
216 allocate_memory(&memory_buf, &memory_bufsize);
217
218 if (!load_sc_file(&sc_file, link_filename, true,
219 memory_buf, memory_bufsize)) {
220 DEBUGF("Could not load %s\n", link_filename);
221 return PLUGIN_ERROR;
222 }
223 if (sc_file.entry_cnt==0) {
224 rb->splash(HZ*2, "No shortcuts in the file!");
225 return PLUGIN_OK;
226 } else if ((sc_file.entry_cnt==1) && user_file) {
227 /* if there's only one entry in the user .link file,
228 * go straight to it without displaying the menu
229 * thus allowing 'quick links' */
230 goto_entry(sc_file.entries[0].path);
231 return PLUGIN_OK;
232 }
233
234 do {
235 /* Display a menu to choose between the entries */
236 leave_loop = list_sc(!user_file);
237 } while (!leave_loop);
238
239 return usb_connected ? PLUGIN_USB_CONNECTED : PLUGIN_OK;
240}