File Manager / src / view /

list-view.c

  1. /*
  2. * Copyright 2014 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17.  
  18. #include "view/list-view.h"
  19. #include "view/ctrl-bar-view.h"
  20. #include "view/genlist-widget.h"
  21. #include "view/navi-path-widget.h"
  22. #include "view/navi-bar-title.h"
  23. #include "view/navigator.h"
  24. #include "view/popup.h"
  25. #include "utils/app-types.h"
  26. #include "utils/ui-utils.h"
  27. #include "utils/common-utils.h"
  28. #include "utils/model-utils.h"
  29. #include "utils/config.h"
  30. #include "utils/logger.h"
  31. #include "model/fs-manager.h"
  32. #include "model/clipboard.h"
  33. #include "model/navi-path-storage.h"
  34. #include "main-app.h"
  35.  
  36. typedef struct {
  37. view_data list_view;
  38. title_widget *title_wgt;
  39. genlist_widget *genlist_wgt;
  40. ctrl_bar_widget *ctrl_bar_wgt;
  41. navi_path_widget *navi_path_wgt;
  42. Eina_List *file_list;
  43. } list_view_data;
  44.  
  45. typedef struct {
  46. list_view_data *list_view;
  47. Evas_Object *wait_popup;
  48. } oper_callback_data;
  49.  
  50. static const char *const PROGRESS_TEXT = "Operation in progress";
  51.  
  52. static int _list_view_create_widgets(list_view_data *lv_data);
  53. static int _list_view_update_content(list_view_data *lv_data);
  54. static void _list_view_destroy(list_view_data *lv_data);
  55.  
  56. static void _list_view_del_cb(void *data, Evas *evas, Evas_Object *obj, void *event_info);
  57. static void _list_view_operation_complete(void *data, int result);
  58. static void _list_view_operation_move_cb(void *data, int result);
  59. static void _list_view_operation_copy_cb(void *data, int result);
  60. static void _list_view_operation_delete_cb(void *data, int result);
  61. static oper_callback_data *_list_view_oper_cb_data_create(list_view_data* lv_data);
  62. static void _list_view_oper_cb_data_destroy(oper_callback_data *data);
  63. static Evas_Object *_list_view_progress_popup_create(list_view_data *lv_data);
  64. static void _progress_popup_back_button_cb(void *data, Evas_Object *obj, void *event_info);
  65.  
  66. int list_view_add(app_data *app, Evas_Object *parent, const char *path, const char *dir_name)
  67. {
  68. RETVM_IF(!app, RESULT_TYPE_INVALID_ARG, "App object is NULL");
  69. RETVM_IF(!parent, RESULT_TYPE_INVALID_ARG, "Parent object is NULL");
  70. RETVM_IF(!path, RESULT_TYPE_INVALID_ARG, "Path is NULL");
  71.  
  72. app->status.is_mainview = EINA_FALSE;
  73.  
  74. list_view_data *data = calloc(1, sizeof(list_view_data));
  75. RETVM_IF(!data, RESULT_TYPE_FAIL_ALLOCATE_MEMORY, "Fail allocate memory");
  76.  
  77. data->list_view.app = app;
  78. data->list_view.navi = parent;
  79. data->list_view.curr_path = (dir_name) ? common_util_strconcat(path, "/", dir_name, NULL)
  80. : strdup(path);
  81. data->list_view.is_root = model_utils_is_root_path(data->list_view.curr_path);
  82.  
  83. data->file_list = NULL;
  84.  
  85. data->list_view.navi_layout = ui_utils_layout_add(data->list_view.navi, _list_view_del_cb, data);
  86. if (!data->list_view.navi_layout) {
  87. ERR("Fail to create Layout");
  88. _list_view_destroy(data);
  89. return RESULT_TYPE_FAIL;
  90. }
  91.  
  92. elm_layout_file_set(data->list_view.navi_layout, ui_utils_get_resource(FM_LAYOUT_EDJ), "navi_layout");
  93.  
  94. int result = fs_manager_get_file_list(data->list_view.app->manager, data->list_view.curr_path, &data->file_list);
  95. if (result != RESULT_TYPE_OK) {
  96. ERR("Fail to get file list");
  97. evas_object_del(data->list_view.navi_layout);
  98. return result;
  99. }
  100.  
  101. const char *title = ui_utils_title_get(data->list_view.curr_path);
  102. result = navigator_add_view(data->list_view.app->navigator, title, &data->list_view);
  103. if (result != RESULT_TYPE_OK) {
  104. ERR("Fail to add view to naviframe");
  105. evas_object_del(data->list_view.navi_layout);
  106. return result;
  107. }
  108.  
  109. result = _list_view_create_widgets(data);
  110. if (result != RESULT_TYPE_OK) {
  111. ERR("Fail to create widgets");
  112. evas_object_del(data->list_view.navi_layout);
  113. return result;
  114. }
  115.  
  116. Eina_List *path_list = NULL;
  117. int res = navi_path_storage_get_path_list(app->path_storage, &path_list);
  118. RETVM_IF(res != RESULT_TYPE_OK, res, "Fail get folders list for navigation widget");
  119. navi_path_widget_content_set(data->navi_path_wgt, path_list);
  120.  
  121. elm_object_item_data_set(data->list_view.navi_item, data);
  122.  
  123. return RESULT_TYPE_OK;
  124. }
  125.  
  126. int list_view_update(Elm_Object_Item *navi_item, int update_options)
  127. {
  128. RETVM_IF(!navi_item, RESULT_TYPE_INVALID_ARG, "View object is NULL");
  129.  
  130. list_view_data *data = elm_object_item_data_get(navi_item);
  131. RETVM_IF(!data, RESULT_TYPE_INVALID_ARG, "Data is NULL");
  132. RETVM_IF(!data->genlist_wgt, RESULT_TYPE_INVALID_ARG, "Genlist widget is NULL");
  133. RETVM_IF(!data->ctrl_bar_wgt, RESULT_TYPE_INVALID_ARG, "Ctrl bar widget is NULL");
  134.  
  135. if (update_options & UPDATE_TYPE_VIEW) {
  136. RETVM_IF(_list_view_update_content(data) != RESULT_TYPE_OK,
  137. RESULT_TYPE_FAIL, "Fail to update view content");
  138. }
  139.  
  140. if (update_options & UPDATE_TYPE_GENLIST) {
  141. RETVM_IF(genlist_widget_update(data->genlist_wgt) != RESULT_TYPE_OK,
  142. RESULT_TYPE_FAIL, "Fail to update genlist widget");
  143. }
  144.  
  145. if (update_options & UPDATE_TYPE_CTRL_BAR_MODE) {
  146. RETVM_IF(ctrl_bar_widget_mode_update(data->ctrl_bar_wgt) != RESULT_TYPE_OK,
  147. RESULT_TYPE_FAIL, "Fail to update ctrl bar");
  148. }
  149.  
  150. if (update_options & UPDATE_TYPE_CTRL_BAR_STATE) {
  151. RETVM_IF(ctrl_bar_widget_state_update(data->ctrl_bar_wgt) != RESULT_TYPE_OK,
  152. RESULT_TYPE_FAIL, "Fail to update ctrl bar");
  153. }
  154.  
  155. return RESULT_TYPE_OK;
  156. }
  157.  
  158. unsigned int list_view_items_count_get(view_data *view)
  159. {
  160. list_view_data *data = (list_view_data *)view;
  161.  
  162. return eina_list_count(data->file_list);
  163. }
  164.  
  165. int list_view_create_folder(view_data *view, const char *folder_name)
  166. {
  167. RETVM_IF(!view, RESULT_TYPE_INVALID_ARG, "View object is NULL");
  168.  
  169. char *new_folder = common_util_strconcat(view->curr_path, "/", folder_name, NULL);
  170.  
  171. int res = fs_manager_create_folder(view->app->manager, new_folder);
  172.  
  173. free(new_folder);
  174. RETVM_IF(res != RESULT_TYPE_OK, res, "Model create folder Fail");
  175.  
  176. return RESULT_TYPE_OK;
  177. }
  178.  
  179. static void _progress_popup_back_button_cb(void *data, Evas_Object *obj, void *event_info)
  180. {
  181. }
  182.  
  183. Evas_Object *_list_view_progress_popup_create(list_view_data *lv_data)
  184. {
  185. RETVM_IF(!lv_data, NULL, "View obj is NULL");
  186.  
  187. Evas_Object *popup = elm_popup_add(lv_data->list_view.navi);
  188. RETVM_IF(!popup, NULL, "Fail to create popup");
  189.  
  190. elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
  191.  
  192. Evas_Object *layout = ui_utils_layout_add(popup, NULL, NULL);
  193. if (!layout) {
  194. ERR("Fail to create layout");
  195. evas_object_del(popup);
  196. return NULL;
  197. }
  198. elm_layout_file_set(layout, ui_utils_get_resource(FM_LAYOUT_EDJ), "processing_view");
  199.  
  200. Evas_Object *progressbar = elm_progressbar_add(layout);
  201. if (!progressbar) {
  202. ERR("Fail to create process bar");
  203. evas_object_del(popup);
  204. return NULL;
  205. }
  206.  
  207. elm_object_style_set(progressbar, "process_medium");
  208. elm_progressbar_pulse(progressbar, EINA_TRUE);
  209. evas_object_show(progressbar);
  210.  
  211. elm_object_part_content_set(layout, "processing", progressbar);
  212. elm_object_part_text_set(layout, "elm.text", PROGRESS_TEXT);
  213.  
  214. evas_object_show(layout);
  215.  
  216. eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, _progress_popup_back_button_cb, NULL);
  217. elm_object_content_set(popup, layout);
  218.  
  219. evas_object_show(popup);
  220.  
  221. return popup;
  222. }
  223.  
  224. static oper_callback_data *_list_view_oper_cb_data_create(list_view_data* lv_data)
  225. {
  226. RETVM_IF(!lv_data, NULL, "View data is NULL");
  227.  
  228. oper_callback_data *cb_data = calloc(1, sizeof(oper_callback_data));
  229. RETVM_IF(!cb_data, NULL, "Failed to allocate memory for callback data");
  230.  
  231. Evas_Object *progress_popup = _list_view_progress_popup_create(lv_data);
  232. if (!progress_popup) {
  233. ERR("Failed to create progress popup");
  234. _list_view_oper_cb_data_destroy(cb_data);
  235. return NULL;
  236. }
  237.  
  238. cb_data->list_view = lv_data;
  239. cb_data->wait_popup = progress_popup;
  240.  
  241. return cb_data;
  242. }
  243.  
  244. static void _list_view_oper_cb_data_destroy(oper_callback_data *data)
  245. {
  246. if (data) {
  247. evas_object_del(data->wait_popup);
  248. free(data);
  249. }
  250. }
  251.  
  252. int list_view_delete_items(view_data *view)
  253. {
  254. RETVM_IF(!view, RESULT_TYPE_INVALID_ARG, "View object is NULL");
  255.  
  256. list_view_data *list_data = (list_view_data *)view;
  257.  
  258. oper_callback_data *cb_data = _list_view_oper_cb_data_create(list_data);
  259. RETVM_IF(!cb_data, RESULT_TYPE_FAIL, "Failed to create callback data");
  260.  
  261. int res = fs_manager_delete_files(list_data->list_view.app->manager,
  262. list_data->file_list,
  263. _list_view_operation_delete_cb,
  264. cb_data);
  265.  
  266. if (res != RESULT_TYPE_OK) {
  267. ERR("Failed to delete selected files");
  268. _list_view_oper_cb_data_destroy(cb_data);
  269. return res;
  270. }
  271.  
  272. return res;
  273. }
  274.  
  275. int list_view_copy_items(view_data *view)
  276. {
  277. RETVM_IF(!view, RESULT_TYPE_INVALID_ARG, "View object is NULL");
  278.  
  279. list_view_data *list_data = (list_view_data *)view;
  280. app_data *app = list_data->list_view.app;
  281.  
  282. int res = clipboard_add_data(app->clipboard, list_data->file_list);
  283. RETVM_IF(res != RESULT_TYPE_OK, res, "Fail to copy files");
  284.  
  285. res = clipboard_set_operation(app->clipboard, OPERATION_TYPE_COPY);
  286. RETVM_IF(res != RESULT_TYPE_OK, res, "Fail to set operation");
  287.  
  288. return RESULT_TYPE_OK;
  289. }
  290.  
  291. int list_view_move_items(view_data *view)
  292. {
  293. RETVM_IF(!view, RESULT_TYPE_INVALID_ARG, "View object is NULL");
  294.  
  295. list_view_data *list_data = (list_view_data *)view;
  296. app_data *app = list_data->list_view.app;
  297.  
  298. int res = clipboard_add_data(app->clipboard, list_data->file_list);
  299. RETVM_IF(res != RESULT_TYPE_OK, res, "Fail to copy files");
  300.  
  301. res = clipboard_set_operation(app->clipboard, OPERATION_TYPE_MOVE);
  302. RETVM_IF(res != RESULT_TYPE_OK, res, "Fail to set operation");
  303.  
  304. return RESULT_TYPE_OK;
  305. }
  306.  
  307. int list_view_past_items(view_data *view)
  308. {
  309. RETVM_IF(!view, RESULT_TYPE_INVALID_ARG, "View object is NULL");
  310.  
  311. list_view_data *list_data = (list_view_data *)view;
  312. app_data *app = list_data->list_view.app;
  313.  
  314. Eina_List *clipboard_list = NULL;
  315. int res = clipboard_get_data(app->clipboard, &clipboard_list);
  316. RETVM_IF(res != RESULT_TYPE_OK || !clipboard_list, res, "Fail to get files from clipboard");
  317.  
  318. operation_type operation = OPERATION_TYPE_NONE;
  319. res = clipboard_get_operation(app->clipboard, &operation);
  320. RETVM_IF(res != RESULT_TYPE_OK, res, "Fail to get operation type");
  321.  
  322. oper_callback_data *cb_data = _list_view_oper_cb_data_create(list_data);
  323. RETVM_IF(!cb_data, RESULT_TYPE_FAIL, "Failed to create callback data");
  324.  
  325. if (operation == OPERATION_TYPE_COPY) {
  326. res = fs_manager_copy_files(app->manager,
  327. clipboard_list,
  328. list_data->list_view.curr_path,
  329. _list_view_operation_copy_cb,
  330. cb_data);
  331. } else if (operation == OPERATION_TYPE_MOVE) {
  332. res = fs_manager_move_files(app->manager,
  333. clipboard_list,
  334. list_data->list_view.curr_path,
  335. _list_view_operation_move_cb,
  336. cb_data);
  337. } else {
  338. ERR("Wrong operation type");
  339. res = RESULT_TYPE_FAIL;
  340. }
  341.  
  342. if (res != RESULT_TYPE_OK) {
  343. ERR("Failed to paste selected files");
  344. _list_view_oper_cb_data_destroy(cb_data);
  345. return res;
  346. }
  347.  
  348. return res;
  349. }
  350.  
  351. int list_view_select_all(view_data *view, Eina_Bool state)
  352. {
  353. RETVM_IF(!view, RESULT_TYPE_INVALID_ARG, "View object is NULL");
  354.  
  355. list_view_data *data = (list_view_data *)view;
  356.  
  357. Eina_List *list = NULL;
  358. void *item = NULL;
  359.  
  360. EINA_LIST_FOREACH(data->file_list, list, item) {
  361. node_info *node = item;
  362. node->is_selected = state;
  363. }
  364. return RESULT_TYPE_OK;
  365. }
  366.  
  367. static int _list_view_create_widgets(list_view_data *lv_data)
  368. {
  369. lv_data->navi_path_wgt = navi_path_widget_add((view_data *)lv_data);
  370. RETVM_IF(!lv_data->navi_path_wgt, RESULT_TYPE_FAIL, "Fail to create navigation widget");
  371.  
  372. lv_data->genlist_wgt = genlist_widget_add((view_data *)lv_data);
  373. RETVM_IF(!lv_data->genlist_wgt, RESULT_TYPE_FAIL, "Fail to create genlist widget");
  374. genlist_widget_content_set(lv_data->genlist_wgt, lv_data->file_list);
  375.  
  376. lv_data->ctrl_bar_wgt = ctrl_bar_widget_add((view_data *)lv_data);
  377. RETVM_IF(!lv_data->ctrl_bar_wgt, RESULT_TYPE_FAIL, "Fail to create ctrl bar widget");
  378.  
  379. if (!lv_data->list_view.is_root) {
  380. lv_data->title_wgt = navi_bar_title_widget_add((view_data *)lv_data);
  381. RETVM_IF(!lv_data->title_wgt, RESULT_TYPE_FAIL, "Fail to create title widget");
  382. }
  383.  
  384. return RESULT_TYPE_OK;
  385. }
  386.  
  387. static int _list_view_update_content(list_view_data *lv_data)
  388. {
  389. common_util_clear_file_list(&lv_data->file_list);
  390.  
  391. int result = fs_manager_get_file_list(lv_data->list_view.app->manager, lv_data->list_view.curr_path, &lv_data->file_list);
  392. RETVM_IF(result != RESULT_TYPE_OK, result, "Fail to get file list");
  393.  
  394. genlist_widget_clear(lv_data->genlist_wgt);
  395. genlist_widget_content_set(lv_data->genlist_wgt, lv_data->file_list);
  396.  
  397. return RESULT_TYPE_OK;
  398. }
  399.  
  400. static void _list_view_operation_move_cb(void *data, int result)
  401. {
  402. _list_view_operation_complete(data, result);
  403. }
  404. static void _list_view_operation_copy_cb(void *data, int result)
  405. {
  406. _list_view_operation_complete(data, result);
  407. }
  408. static void _list_view_operation_delete_cb(void *data, int result)
  409. {
  410. RETM_IF(!data, "Data is NULL");
  411.  
  412. oper_callback_data *cb_data = (oper_callback_data *)data;
  413. list_view_data *list_data = cb_data->list_view;
  414.  
  415. _list_view_oper_cb_data_destroy(cb_data);
  416.  
  417. if (result != RESULT_TYPE_OK) {
  418. RETM_IF(popup_create((view_data *)list_data, POPUP_TYPE_ERROR), "Fail to create error popup");
  419. } else {
  420. list_data->list_view.app->status.curr_mode = MODE_DEFAULT;
  421. int res = list_view_update(list_data->list_view.navi_item,
  422. UPDATE_TYPE_GENLIST |
  423. UPDATE_TYPE_CTRL_BAR_MODE |
  424. UPDATE_TYPE_VIEW);
  425.  
  426. RETM_IF(res != RESULT_TYPE_OK, "Fail to update view");
  427. }
  428. }
  429.  
  430. static void _list_view_operation_complete(void *data, int result)
  431. {
  432. RETM_IF(!data, "Data is NULL");
  433.  
  434. oper_callback_data *cb_data = (oper_callback_data *)data;
  435. list_view_data *list_data = cb_data->list_view;
  436.  
  437. _list_view_oper_cb_data_destroy(cb_data);
  438.  
  439. if (result != RESULT_TYPE_OK) {
  440. ERR("File operation failed");
  441.  
  442. operation_type operation = OPERATION_TYPE_NONE;
  443. int res = clipboard_get_operation(list_data->list_view.app->clipboard, &operation);
  444.  
  445. if (res != RESULT_TYPE_OK) {
  446. ERR("Fail to get operation type");
  447. res = popup_create((view_data *)list_data, POPUP_TYPE_ERROR);
  448. } else {
  449. switch (operation) {
  450. case OPERATION_TYPE_MOVE:
  451. if (result == RESULT_TYPE_OPERATION_INVALID_DEST) {
  452. res = popup_create((view_data *)list_data, POPUP_TYPE_MOVE_RECURSIVE_FAIL);
  453. } else {
  454. res = popup_create((view_data *)list_data, POPUP_TYPE_FAIL_TO_MOVE);
  455. }
  456. break;
  457. case OPERATION_TYPE_COPY:
  458. if (result == RESULT_TYPE_OPERATION_INVALID_DEST) {
  459. res = popup_create((view_data *)list_data, POPUP_TYPE_COPY_RECURSIVE_FAIL);
  460. } else {
  461. res = popup_create((view_data *)list_data, POPUP_TYPE_FAIL_TO_COPY);
  462. }
  463. break;
  464. default:
  465. res = popup_create((view_data *)list_data, POPUP_TYPE_ERROR);
  466. break;
  467. }
  468. }
  469.  
  470. if (res != RESULT_TYPE_OK) {
  471. ERR("Fail to create error popup");
  472. }
  473. } else {
  474. list_data->list_view.app->status.curr_mode = MODE_DEFAULT;
  475. int res = list_view_update(list_data->list_view.navi_item,
  476. UPDATE_TYPE_GENLIST |
  477. UPDATE_TYPE_CTRL_BAR_MODE |
  478. UPDATE_TYPE_VIEW);
  479.  
  480. if (res != RESULT_TYPE_OK) {
  481. ERR("Fail to update view");
  482. }
  483. }
  484.  
  485. if (result != RESULT_TYPE_OPERATION_INVALID_DEST) {
  486. result = clipboard_clear(list_data->list_view.app->clipboard);
  487. RETM_IF(result != RESULT_TYPE_OK, "Fail to clear clipboard");
  488. }
  489. }
  490.  
  491. static void _list_view_destroy(list_view_data *lv_data)
  492. {
  493. if (lv_data) {
  494. app_data *app = lv_data->list_view.app;
  495.  
  496. app->status.curr_mode = MODE_DEFAULT;
  497.  
  498. common_util_clear_file_list(&lv_data->file_list);
  499.  
  500. free(lv_data->list_view.curr_path);
  501. free(lv_data);
  502. }
  503. }
  504.  
  505. static void _list_view_del_cb(void *data, Evas *evas, Evas_Object *obj, void *event_info)
  506. {
  507. _list_view_destroy(data);
  508. }