PageRenderTime 97ms CodeModel.GetById 30ms app.highlight 49ms RepoModel.GetById 12ms app.codeStats 0ms

/src/ftk_file_browser.c

http://ftk.googlecode.com/
C | 602 lines | 481 code | 89 blank | 32 comment | 93 complexity | 4986bce1e99be1722c454f5bd326d375 MD5 | raw file
  1/*
  2 * File: ftk_file_browser.c
  3 * Author: Li XianJing <xianjimli@hotmail.com>
  4 * Brief:  file browser window for file manager and choose.
  5 *
  6 * Copyright (c) 2009 - 2010  Li XianJing <xianjimli@hotmail.com>
  7 *
  8 * Licensed under the Academic Free License version 2.1
  9 *
 10 * This program is free software; you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License as published by
 12 * the Free Software Foundation; either version 2 of the License, or
 13 * (at your option) any later version.
 14 *
 15 * This program is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 * GNU General Public License for more details.
 19 *
 20 * You should have received a copy of the GNU General Public License
 21 * along with this program; if not, write to the Free Software
 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 23 */
 24
 25/*
 26 * History:
 27 * ================================================================
 28 * 2010-08-15 Li XianJing <xianjimli@hotmail.com> created
 29 *
 30 */
 31
 32#include "ftk_log.h"
 33#include "ftk_util.h"
 34#include "ftk_theme.h"
 35#include "ftk_entry.h"
 36#include "ftk_button.h"
 37#include "ftk_dialog.h"
 38#include "ftk_globals.h"
 39#include "ftk_menu_item.h"
 40#include "ftk_list_view.h"
 41#include "ftk_menu_panel.h"
 42#include "ftk_app_window.h"
 43#include "ftk_message_box.h"
 44#include "ftk_file_system.h"
 45#include "ftk_file_browser.h"
 46#include "ftk_list_render_default.h"
 47#include "ftk_list_model_default.h"
 48
 49typedef struct _FileBrowserPrivInfo
 50{
 51	FtkListModel* model;
 52	FtkWidget* list_view;
 53	void* on_choosed_ctx;
 54	char* filter_mime_type;
 55	FtkFileBrowserType type;
 56	char path[FTK_MAX_PATH+1];
 57	FtkFileBrowserOnChoosed on_choosed;
 58}PrivInfo;
 59
 60static void priv_info_destroy(void* obj)
 61{
 62	PrivInfo* priv = (PrivInfo*)obj;
 63
 64	FTK_FREE(priv);
 65
 66	return;
 67}
 68
 69static Ret ftk_file_browser_on_quit(void* ctx, void* obj)
 70{
 71	ftk_widget_unref((FtkWidget*)ctx);
 72	
 73	return RET_OK;
 74}
 75
 76static Ret ftk_file_browser_on_ok(void* ctx, void* obj)
 77{
 78	int i = 0;
 79	FtkWidget* win = (FtkWidget*)ctx;
 80	FtkListItemInfo* info = NULL;
 81	char path[FTK_MAX_PATH+1] = {0};
 82	PrivInfo* priv = (PrivInfo*)ftk_widget_user_data(win);
 83	return_val_if_fail(priv != NULL && priv->on_choosed != NULL, RET_FAIL);
 84
 85	if(priv->type == FTK_FILE_BROWER_SINGLE_CHOOSER)
 86	{
 87		i = ftk_list_view_get_selected(priv->list_view);
 88		ftk_list_model_get_data(priv->model, i, (void**)&info);
 89		if(info != NULL)
 90		{
 91			ftk_strs_cat(path, FTK_MAX_PATH, priv->path, "/", info->text, NULL);
 92			priv->on_choosed(priv->on_choosed_ctx, 0, path);
 93		}
 94	}
 95	else
 96	{
 97		int index = 0;
 98		int n = ftk_list_model_get_total(priv->model);
 99		for(i = 0; i < n; i++)
100		{
101			ftk_list_model_get_data(priv->model, i, (void**)&info);
102			if(info != NULL && info->state)
103			{
104				ftk_strs_cat(path, FTK_MAX_PATH, priv->path, "/", info->text, NULL);
105				priv->on_choosed(priv->on_choosed_ctx, index++, path);
106			}
107		}
108		priv->on_choosed(priv->on_choosed_ctx, -1, NULL);
109	}
110	ftk_widget_unref((FtkWidget*)ctx);
111	
112	return RET_OK;
113}
114
115static Ret ftk_file_browser_on_cancel(void* ctx, void* obj)
116{
117	ftk_widget_unref((FtkWidget*)ctx);
118	
119	return RET_OK;
120}
121
122static Ret ftk_file_browser_on_prepare_options_menu_for_choose(void* ctx, FtkWidget* menu_panel)
123{
124	FtkWidget* item = NULL;
125	
126	item = ftk_menu_item_create(menu_panel);
127	ftk_widget_set_text(item, _("OK"));
128	ftk_menu_item_set_clicked_listener(item, ftk_file_browser_on_ok, ctx);
129	ftk_widget_show(item, 1);
130	
131	item = ftk_menu_item_create(menu_panel);
132	ftk_widget_set_text(item, _("Cancel"));
133	ftk_menu_item_set_clicked_listener(item, ftk_file_browser_on_cancel, ctx);
134	ftk_widget_show(item, 1);
135
136	return	RET_OK;
137}
138
139static Ret ftk_file_browser_on_remove(void* ctx, void* obj)
140{
141	int i = 0;
142	int ret = 0;
143	const char* buttons[3];
144	FtkWidget* win = (FtkWidget*)ctx;
145	FtkListItemInfo* info = NULL;
146	PrivInfo* priv = (PrivInfo*)ftk_widget_user_data(win);
147	char message[FTK_MAX_PATH + 30] = {0};
148	buttons[0] = _("Yes");
149	buttons[1] = _("No");
150	buttons[2] = NULL;
151		
152	i = ftk_list_view_get_selected(priv->list_view);
153	ftk_list_model_get_data(priv->model, i, (void**)&info);
154	return_val_if_fail(info != NULL, RET_FAIL);
155	
156	if(strcmp(info->text, _("..")) == 0)
157	{
158		return RET_FAIL;
159	}
160
161	ftk_strs_cat(message, sizeof(message), _("Are you sure to remove:\n "), info->text, NULL);
162
163	if((ret = ftk_question(_("Remove"), message, buttons)) == 1)
164	{
165		char path[FTK_MAX_PATH+1] = {0};
166		ftk_strs_cat(path, FTK_MAX_PATH, priv->path, "/", info->text, NULL);
167		if(ftk_fs_delete(path) == RET_OK)
168		{
169			ftk_list_model_remove(priv->model, i);
170		}
171		else
172		{
173			ftk_strs_cat(message, sizeof(message), _("Remove failed:\n"), info->text, NULL);
174			ftk_tips(message);
175		}
176	}
177	
178	return RET_OK;
179}
180
181static Ret ftk_file_browser_input_dialog_button_clicked(void* ctx, void* obj)
182{
183	return RET_QUIT;
184}
185
186enum _WidgetId
187{
188	ID_OK = 1,
189	ID_CANCEL = 2,
190	ID_ENTRY = 3
191};
192
193static FtkWidget* ftk_file_browser_input_dialog(FtkWidget* thiz, const char* text)
194{
195	int dialog_width = 0;
196	FtkWidget* win = thiz;
197	FtkWidget* entry = NULL;
198	FtkWidget* button = NULL;
199	FtkWidget* dialog = NULL;
200
201	dialog = ftk_dialog_create(0, 0, ftk_widget_width(win) - 20, 150);
202	dialog_width = ftk_widget_width(dialog);
203	entry = ftk_entry_create(dialog, 10, 20, dialog_width - 20, 20);
204	ftk_widget_set_id(entry, ID_ENTRY);
205	
206	button = ftk_button_create(dialog, dialog_width/2-70, 60, 80, 50);
207	ftk_widget_set_text(button, _("OK"));
208	ftk_widget_set_id(button, ID_OK);
209	ftk_button_set_clicked_listener(button, ftk_file_browser_input_dialog_button_clicked, NULL);
210
211	button = ftk_button_create(dialog, dialog_width/2+10, 60, 80, 50);
212	ftk_widget_set_text(button, _("Cancel"));
213	ftk_widget_set_id(button, ID_CANCEL);
214	ftk_button_set_clicked_listener(button, ftk_file_browser_input_dialog_button_clicked, NULL);
215	
216	ftk_window_set_focus(dialog, entry);
217	ftk_widget_set_text(dialog, text);
218	ftk_widget_show_all(dialog, 1);
219
220	return dialog;
221}
222
223static Ret ftk_file_browser_on_rename(void* ctx, void* obj)
224{
225	int i = 0;
226	int ret = 0;
227	const char* name = NULL;
228	FtkWidget* win = (FtkWidget*)ctx;
229	FtkWidget* dialog = NULL;
230	FtkListItemInfo* info = NULL;
231	PrivInfo* priv = (PrivInfo*)ftk_widget_user_data(win);
232	i = ftk_list_view_get_selected(priv->list_view);
233	ftk_list_model_get_data(priv->model, i, (void**)&info);
234	return_val_if_fail(info != NULL, RET_FAIL);
235	
236	if(strcmp(info->text, _("..")) == 0)
237	{
238		return RET_FAIL;
239	}
240
241	dialog = ftk_file_browser_input_dialog(win, _("Please input new name:"));
242	ret = ftk_dialog_run(dialog);
243	if(ret == ID_OK)
244	{
245		name = ftk_entry_get_text(ftk_widget_lookup(dialog, ID_ENTRY));
246		if(name != NULL)
247		{
248			char new_name[FTK_MAX_PATH+1] = {0};
249			char old_name[FTK_MAX_PATH+1] = {0};
250			ftk_strs_cat(old_name, FTK_MAX_PATH, priv->path, "/", info->text, NULL);
251			ftk_strs_cat(new_name, FTK_MAX_PATH, priv->path, "/", name, NULL);
252
253			if(ftk_fs_move(old_name, new_name) == RET_OK)
254			{
255				ftk_file_browser_load(win);
256			}
257			else
258			{
259				ftk_tips(_("Rename failed."));
260			}
261			ftk_logd("%s: %s --> %s\n", __func__, old_name, new_name);
262		}
263	}
264	ftk_widget_unref(dialog);
265
266	ftk_logd("%s: ret=%d\n", __func__, ret);
267
268	return RET_OK;
269}
270
271static Ret ftk_file_browser_on_create_folder(void* ctx, void* obj)
272{
273	int ret = 0;
274	const char* name = NULL;
275	FtkWidget* win = (FtkWidget*)ctx;
276	FtkWidget* dialog = NULL;
277	PrivInfo* priv = (PrivInfo*)ftk_widget_user_data(win);
278		
279	dialog = ftk_file_browser_input_dialog(win, _("Please input folder name:"));
280	ret = ftk_dialog_run(dialog);
281	if(ret == ID_OK)
282	{
283		name = ftk_entry_get_text(ftk_widget_lookup(dialog, ID_ENTRY));
284		if(name != NULL)
285		{
286			char folder_name[FTK_MAX_PATH+1] = {0};
287			ftk_strs_cat(folder_name, FTK_MAX_PATH, priv->path, "/", name, NULL);
288			
289			if(ftk_fs_create_dir(folder_name) == RET_OK)
290			{
291				ftk_file_browser_load(win);
292			}
293			else
294			{
295				ftk_tips(_("Create folder failed."));
296			}
297			ftk_logd("%s: create %s\n", __func__, folder_name);
298		}
299	}
300	ftk_widget_unref(dialog);
301
302	ftk_logd("%s: ret=%d\n", __func__, ret);
303
304	return RET_OK;
305}
306
307static Ret ftk_file_browser_on_detail(void* ctx, void* obj)
308{
309	/*TODO*/
310	return RET_OK;
311}
312
313static Ret ftk_file_browser_on_more(void* ctx, void* obj)
314{
315	/*TODO*/
316	return RET_OK;
317}
318
319static Ret ftk_file_browser_on_prepare_options_menu(void* ctx, FtkWidget* menu_panel)
320{
321	FtkWidget* item = ftk_menu_item_create(menu_panel);
322	ftk_widget_set_text(item, _("Remove"));
323	ftk_menu_item_set_clicked_listener(item, ftk_file_browser_on_remove, ctx);
324	ftk_widget_show(item, 1);
325	
326	item = ftk_menu_item_create(menu_panel);
327	ftk_widget_set_text(item, _("Rename"));
328	ftk_menu_item_set_clicked_listener(item, ftk_file_browser_on_rename, ctx);
329	ftk_widget_show(item, 1);
330	
331	item = ftk_menu_item_create(menu_panel);
332	ftk_widget_set_text(item, _("Create Folder"));
333	ftk_menu_item_set_clicked_listener(item, ftk_file_browser_on_create_folder, ctx);
334	ftk_widget_show(item, 1);
335	
336	item = ftk_menu_item_create(menu_panel);
337	ftk_widget_set_text(item, _("Detail"));
338	ftk_menu_item_set_clicked_listener(item, ftk_file_browser_on_detail, ctx);
339	ftk_widget_show(item, 1);
340	
341	item = ftk_menu_item_create(menu_panel);
342	ftk_widget_set_text(item, _("Quit"));
343	ftk_menu_item_set_clicked_listener(item, ftk_file_browser_on_quit, ctx);
344	ftk_widget_show(item, 1);
345	
346	item = ftk_menu_item_create(menu_panel);
347	ftk_widget_set_text(item, _("More"));
348	ftk_menu_item_set_clicked_listener(item, ftk_file_browser_on_more, ctx);
349	ftk_widget_show(item, 1);
350
351	return	RET_OK;
352}
353
354static Ret ftk_file_browser_on_item_clicked(void* ctx, void* list)
355{
356	FtkWidget* win = (FtkWidget*)ctx;
357	FtkListItemInfo* info = NULL;
358	int i = ftk_list_view_get_selected((FtkWidget*)list);
359	PrivInfo* priv = (PrivInfo*)ftk_widget_user_data(win);
360	FtkListModel* model = ftk_list_view_get_model((FtkWidget*)list);
361 
362 	return_val_if_fail(priv != NULL, RET_FAIL);
363
364	ftk_list_model_get_data(model, i, (void**)&info);
365	if(info != NULL && info->text != NULL)
366	{
367		char* p = NULL;
368		char  path[FTK_MAX_PATH+1] = {0};
369		char* file_name = info->text;
370
371		if(strcmp(file_name, _("..")) == 0)
372		{
373			ftk_strcpy(path, priv->path);
374			if((p = strrchr(path, FTK_PATH_DELIM)) != NULL)
375			{
376				if(p == path)
377				{
378					p[1] = '\0';
379				}
380				else
381				{
382					*p = '\0';
383				}
384			}
385			ftk_file_browser_set_path(win, path);
386			ftk_file_browser_load(win);
387		}
388		else if(info->value) /*enter selected folder*/
389		{
390			ftk_strs_cat(path, FTK_MAX_PATH, priv->path, "/", file_name, NULL);
391			ftk_file_browser_set_path(win, path);
392			ftk_file_browser_load(win);
393		}
394		else if(priv->type == FTK_FILE_BROWER_SINGLE_CHOOSER)
395		{
396			if(priv->on_choosed != NULL)
397			{
398				ftk_strs_cat(path, FTK_MAX_PATH, priv->path, "/", file_name, NULL);
399				priv->on_choosed(priv->on_choosed_ctx, 0, path);
400				ftk_widget_unref(win);
401			}
402		}
403		else if(priv->type == FTK_FILE_BROWER_MULTI_CHOOSER)
404		{
405			info->state = !info->state;
406		}
407	}
408
409	return RET_OK;
410}
411
412FtkWidget* ftk_file_browser_create(FtkFileBrowserType type)
413{
414	FtkListModel* model = NULL;
415	FtkListRender* render = NULL;	
416	FtkPrepareOptionsMenu option_menu = NULL;
417	FtkWidget* win  = ftk_app_window_create();
418	PrivInfo* priv  = FTK_NEW(PrivInfo);
419	FtkWidget* list = ftk_list_view_create(win, 0, 0, ftk_widget_width(win), ftk_widget_height(win));
420
421	if(type == FTK_FILE_BROWER_APP)
422	{
423		option_menu = ftk_file_browser_on_prepare_options_menu;
424	}
425	else
426	{
427		option_menu = ftk_file_browser_on_prepare_options_menu_for_choose;
428	}
429	ftk_app_window_set_on_prepare_options_menu(win, option_menu, win);
430
431	model = ftk_list_model_default_create(10);
432	render = ftk_list_render_default_create();
433
434	priv->type = type;
435	priv->model = model;
436	priv->list_view = list;
437	ftk_list_view_init(list, model, render, 40);
438	ftk_widget_set_text(win, _("File Browser"));
439	ftk_widget_set_user_data(win, priv_info_destroy, priv);
440	ftk_list_view_set_clicked_listener(list, ftk_file_browser_on_item_clicked, win);
441	ftk_list_render_default_set_marquee_attr(render, 
442		FTK_MARQUEE_AUTO | FTK_MARQUEE_RIGHT2LEFT | FTK_MARQUEE_FOREVER);
443	ftk_list_model_unref(model);
444
445	return win;
446}
447
448Ret		   ftk_file_browser_set_path(FtkWidget* thiz, const char* path)
449{
450	PrivInfo* priv = (PrivInfo*)ftk_widget_user_data(thiz);
451	return_val_if_fail(priv != NULL && path != NULL, RET_FAIL);	
452
453	ftk_strncpy(priv->path, path, FTK_MAX_PATH);
454	ftk_normalize_path(priv->path);
455
456	return RET_OK;
457}
458
459Ret		   ftk_file_browser_set_filter(FtkWidget* thiz, const char* mime_type)
460{
461	PrivInfo* priv = (PrivInfo*)ftk_widget_user_data(thiz);
462	return_val_if_fail(priv != NULL, RET_FAIL);	
463
464	FTK_FREE(priv->filter_mime_type);
465	priv->filter_mime_type = FTK_STRDUP(mime_type);
466
467	return RET_OK;
468}
469
470Ret		   ftk_file_browser_set_choosed_handler(FtkWidget* thiz, FtkFileBrowserOnChoosed on_choosed, void* ctx)
471{
472	PrivInfo* priv = (PrivInfo*)ftk_widget_user_data(thiz);
473	return_val_if_fail(priv != NULL, RET_FAIL);	
474
475	priv->on_choosed = on_choosed;
476	priv->on_choosed_ctx = ctx;
477
478	return RET_OK;
479}
480
481static FtkBitmap* ftk_file_browser_load_mime_icon(const char* file_name)
482{
483	char* p = NULL;
484	char icon_name[FTK_MAX_PATH+1] = {0};
485	char mime_type[FTK_MIME_TYPE_LEN + 1] = {0};
486	
487	ftk_strcpy(mime_type, ftk_file_get_mime_type(file_name));
488
489	p = strrchr(mime_type, '/');
490	return_val_if_fail(p != NULL, NULL);
491
492	*p = '\0';
493	ftk_strs_cat(icon_name, FTK_MAX_PATH, "mime_", mime_type, FTK_STOCK_IMG_SUFFIX, NULL);
494
495	return ftk_theme_load_image(ftk_default_theme(), icon_name);
496}
497
498static int ftk_file_browser_get_display_style(PrivInfo* priv, int is_dir)
499{
500	if(priv->type == FTK_FILE_BROWER_APP || priv->type == FTK_FILE_BROWER_SINGLE_CHOOSER)
501	{
502		return FTK_LIST_ITEM_NORMAL;
503	}
504
505	if(priv->filter_mime_type == NULL)
506	{
507		return is_dir ? FTK_LIST_ITEM_NORMAL : FTK_LIST_ITEM_CHECK;	
508	}
509	else
510	{
511		if(strcmp(priv->filter_mime_type, FTK_MIME_DIR) == 0)
512		{
513			return is_dir ? FTK_LIST_ITEM_CHECK: FTK_LIST_ITEM_NORMAL;	
514		}
515		else
516		{
517			return !is_dir ? FTK_LIST_ITEM_CHECK: FTK_LIST_ITEM_NORMAL;	
518		}
519	}
520}
521
522Ret		   ftk_file_browser_load(FtkWidget* thiz)
523{
524	FtkFileInfo info = {0};
525	FtkFsHandle handle = NULL;
526	FtkListItemInfo item = {0};
527	const char* mime_type = NULL;
528	char path[FTK_MAX_PATH+1] = {0};
529	PrivInfo* priv = ftk_widget_user_data(thiz);
530	return_val_if_fail(priv != NULL && priv->path != NULL, RET_FAIL);	
531
532	handle = ftk_dir_open(priv->path);
533	if(handle == NULL)
534	{
535		ftk_logd("%s: open %s\n", __func__, priv->path);
536	}
537	return_val_if_fail(handle != NULL, RET_FAIL);
538
539	ftk_list_model_reset(priv->model);
540	ftk_list_model_disable_notify(priv->model);
541
542	if(!ftk_fs_is_root(priv->path))
543	{
544		item.value = 1;
545		item.text = _("..");
546		item.type = FTK_LIST_ITEM_NORMAL;
547		item.left_icon = ftk_theme_load_image(ftk_default_theme(), "up"FTK_STOCK_IMG_SUFFIX);
548		ftk_list_model_add(priv->model, &item);
549	}
550
551	/*directory go first.*/
552	while(ftk_dir_read(handle, &info) == RET_OK)
553	{
554		if(info.name[0] == '.') continue;
555
556		if(info.is_dir)
557		{
558			item.value = 1;
559			item.text = info.name;
560			item.type = ftk_file_browser_get_display_style(priv, 1);
561			item.left_icon = ftk_theme_load_image(ftk_default_theme(), "folder"FTK_STOCK_IMG_SUFFIX);
562			ftk_list_model_add(priv->model, &item);
563		}
564	}
565	ftk_dir_close(handle);
566
567	if(priv->filter_mime_type == NULL || strcmp(priv->filter_mime_type, FTK_MIME_DIR) != 0)
568	{
569		handle = ftk_dir_open(priv->path);
570		while(ftk_dir_read(handle, &info) == RET_OK)
571		{
572			if(info.name[0] == '.') continue;
573			if(info.is_dir) continue;
574
575			if(priv->filter_mime_type != NULL)
576			{
577				ftk_strs_cat(path, FTK_MAX_PATH, priv->path, "/", info.name, NULL);
578				mime_type = ftk_file_get_mime_type(path);
579				if(strstr(priv->filter_mime_type, mime_type) != NULL)
580				{
581					continue;
582				}
583			}
584				
585			item.value = 0;
586			item.type = ftk_file_browser_get_display_style(priv, 0);
587			item.text = info.name;
588			item.left_icon = ftk_file_browser_load_mime_icon(info.name);
589			ftk_list_model_add(priv->model, &item);
590		}
591		ftk_dir_close(handle);
592	}
593
594	ftk_window_set_focus(thiz, priv->list_view);
595	ftk_list_view_set_cursor(priv->list_view, 0);
596	ftk_list_model_enable_notify(priv->model);
597	ftk_list_model_notify(priv->model);
598	ftk_widget_show_all(thiz, 1);
599
600	return RET_OK;
601}
602