00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "config.h"
00032
00033 #include <ctype.h>
00034 #include <gtk/gtk.h>
00035 #include <stdlib.h>
00036 #include <sys/stat.h>
00037 #include <sys/time.h>
00038 #include <time.h>
00039
00040 #include "ctb_log.h"
00041 #include "filemodel.h"
00042 #include "filetypes.h"
00043 #include "i18n.h"
00044 #include "ipc.h"
00045 #include "menu.h"
00046 #include "shortcut.h"
00047 #include "db.h"
00048 #include "ctb_actions.h"
00049
00050
00051
00052
00053
00054
00055 static const char* order_names[N_CTB_SORT_ORDER] =
00056 {
00057
00058 [CTB_SORT_BY_NAME] = N_("- by title"),
00059
00060 [CTB_SORT_BY_TYPE] = N_("- by type"),
00061
00062 [CTB_SORT_BY_SIZE] = N_("- by size"),
00063
00064 [CTB_SORT_BY_DATE_ADDED] = N_("- by date added"),
00065
00066 [CTB_SORT_BY_DATE_READ] = N_("- recently opened"),
00067
00068 [CTB_SORT_BY_AUTHOR] = N_("- by author"),
00069 };
00070
00071 typedef struct
00072 {
00073 gchar *parent_dir;
00074 gchar *last_item;
00075 } stack_entry_t;
00076
00077 typedef struct
00078 {
00079 const char* title;
00080 const char* tag_filter;
00081 ctb_sort_order_t order;
00082 gboolean fixed_order;
00083 } ViewModeInfo;
00084
00085 #define TAG_BOOK "book"
00086 #define TAG_IMAGE "image"
00087 #define TAG_NEWS "news"
00088 #define TAG_PERSONAL "personal"
00089 #define TAG_HELP "help"
00090 #define TAG_NOTE "note"
00091
00092 static ViewModeInfo g_viewmodes[] =
00093 {
00094
00095 [DESKTOP_VIEW] = { N_("Home"), NULL, CTB_SORT_BY_NAME, TRUE },
00096 [SETTINGS_VIEW] = { N_("Settings"), NULL, CTB_SORT_BY_NAME, TRUE },
00097 [BOOKS_VIEW] = { N_("Books"), TAG_BOOK, CTB_SORT_BY_NAME, FALSE},
00098 [NEWS_VIEW] = { N_("News"), TAG_NEWS, CTB_SORT_BY_DATE_ADDED, FALSE},
00099 [IMAGES_VIEW] = { N_("Images"), TAG_IMAGE, CTB_SORT_BY_NAME, FALSE},
00100 [PERSONAL_VIEW] = { N_("Personal Documents"), TAG_PERSONAL, CTB_SORT_BY_NAME, FALSE},
00101 [DIR_VIEW] = { N_("SD Card"), NULL, CTB_SORT_BY_NAME, FALSE},
00102 [SHORTCUT_VIEW] = { N_("Shortcuts"), NULL, CTB_SORT_BY_NAME, FALSE},
00103 [NOTES_VIEW] = { N_("Notes"), TAG_NOTE, CTB_SORT_BY_DATE_ADDED, FALSE},
00104 [HELP_VIEW] = { N_("Help"), TAG_HELP, CTB_SORT_BY_NAME, FALSE},
00105 [RECENT_VIEW] = { N_("Recently Added"), NULL, CTB_SORT_BY_DATE_ADDED, TRUE },
00106 [SEARCH_VIEW] = { N_("Search Results"), NULL, CTB_SORT_BY_NAME, FALSE},
00107 };
00108
00109
00110
00111
00112
00113 static const char *THUMBNAIL_IMAGE_TYPE = "png";
00114 static int NUM_RECENT_ITEMS = 15;
00115
00116
00117
00118
00119
00120
00121 static GtkListStore *g_filestore = NULL;
00122 static gint g_items_per_page = 1;
00123 static gint g_item_offset = 0;
00124 static gint g_total_items = 0;
00125 static gboolean g_has_next_page = FALSE;
00126 static int g_curpage = 0;
00127 static int g_numpages = 0;
00128 static gboolean g_boundary_check = TRUE;
00129 static ctb_viewmodes_t g_viewmode = BROWSE_MODE;
00130 static int g_desktop_offset = 0;
00131 static int g_desktop_items = 0;
00132
00133 static ctb_sort_order_t g_sort_order = -1;
00134 static gboolean g_is_sort_asc = TRUE;
00135 static filemodel_thumbsize_t g_thumbnail_size= MODTHUMB_MEDIUM;
00136
00137 static gchar *g_current_dir = NULL;
00138 static metadata_table *g_values = NULL;
00139 static GSList *toggled_list = NULL;
00140 static gchar *g_delete_text = NULL;
00141 static time_t g_last_modified = 0;
00142
00143 static GList *g_dir_stack = NULL;
00144
00145 static char g_alpha_list[FILEMODEL_NUM_ALPHA];
00146 static GSList *desktop_names = NULL;
00147
00148 static gchar *g_search_filter = NULL;
00149 static const gchar *g_subtitle = NULL;
00150
00151 #if MACHINE_IS_DR800S || MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
00152 static filelist_entry_t *g_last_read = NULL;
00153 static metadata_table *g_last_read_results = NULL;
00154 #endif
00155
00156
00157 static gboolean g_window_is_on_top = TRUE;
00158 static ViewMode g_viewmode2 = -1;
00159
00160
00161
00162
00163
00164 static gchar* format_size ( const gint64 bytes );
00165 static void load_items_in_model ( void );
00166 static void clear_toggled_list ( void );
00167 static gboolean is_delete_allowed(const gchar* filename, const gchar* dirpath);
00168 static void scroll_to_filename(const gchar *filename);
00169 static void update_alpha_list();
00170 static void clear_dir_stack();
00171 static GdkPixbuf* get_thumbnail(const metadata_cell *cell);
00172 static GdkPixbuf* create_delete_overlay(const GdkPixbuf* source, gboolean toggled);
00173 static int num_specials_per_page();
00174
00175
00176
00177
00178
00179
00180 void filemodel_init()
00181 {
00182 filetypes_init(TRUE);
00183 get_filemodel();
00184 filemodel_set_viewmode2(DESKTOP_VIEW);
00185 }
00186
00187
00188 erMetadb filemodel_get_database()
00189 {
00190 return get_database();
00191 }
00192
00193
00194 static void clear_last_read()
00195 {
00196 #if MACHINE_IS_DR800S || MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
00197 filelist_entry_free(g_last_read);
00198 g_last_read = NULL;
00199 metadata_table_free(g_last_read_results);
00200 g_last_read_results = NULL;
00201 #endif
00202 }
00203
00204
00205 void filemodel_quit()
00206 {
00207 close_database();
00208 if (g_values) metadata_table_free(g_values);
00209 g_values = NULL;
00210 clear_last_read();
00211 clear_toggled_list();
00212 }
00213
00214
00215 GtkTreeModel* get_filemodel()
00216 {
00217 if (g_filestore == NULL)
00218 {
00219 g_filestore = gtk_list_store_new(N_FILEMODEL_COLUMNS, FILEMODEL_COLUMN_TYPES);
00220 }
00221 return GTK_TREE_MODEL(g_filestore);
00222 }
00223
00224
00225 static const char* get_row_filename(const metadata_cell *row)
00226 {
00227 const metadata_cell *cell = row;
00228 if (cell->type != METADATA_TEXT) {
00229 ERRORPRINTF("illegal cell type [%d] for filename", cell->type);
00230 return NULL;
00231 }
00232 return cell->value.v_text->str;
00233 }
00234
00235
00236 static const char* get_row_dirpath(const metadata_cell *row)
00237 {
00238 const metadata_cell *cell = row + 1;
00239 if (cell->type != METADATA_TEXT) {
00240 ERRORPRINTF("illegal cell type [%d] for directory_path", cell->type);
00241 return NULL;
00242 }
00243 return cell->value.v_text->str;
00244 }
00245
00246
00247 static gboolean get_row_is_directory(const metadata_cell *row)
00248 {
00249 const metadata_cell *cell = row + 2;
00250 if (cell->type != METADATA_INT64) {
00251 ERRORPRINTF("illegal cell type [%d] for is_directory", cell->type);
00252 return FALSE;
00253 }
00254 gboolean is_directory = FALSE;
00255 gint64 i64 = cell->value.v_int64;
00256 if (i64 == 1) {
00257 is_directory = TRUE;
00258 } else if (i64 != 0) {
00259 ERRORPRINTF("illegal value [%lld] for is_directory", i64);
00260 }
00261 return is_directory;
00262 }
00263
00264
00265 static const char* get_row_filetype(const metadata_cell *row)
00266 {
00267 const metadata_cell *cell = row + 3;
00268 if (cell->type != METADATA_TEXT) {
00269 ERRORPRINTF("illegal cell type [%d] for file_type", cell->type);
00270 return NULL;
00271 }
00272 return cell->value.v_text->str;
00273 }
00274
00275
00276 static gint64 get_row_filesize(const metadata_cell *row)
00277 {
00278 const metadata_cell *cell = row + 4;
00279 if (cell->type != METADATA_INT64)
00280 {
00281 if (cell->type != METADATA_NULL) {
00282 ERRORPRINTF("illegal cell type [%d] for filesize", cell->type);
00283 }
00284 return 0;
00285 }
00286 gint64 i64 = cell->value.v_int64;
00287 g_assert(i64 >= 0);
00288 return i64;
00289 }
00290
00291
00292 static gint64 get_row_filedate(const metadata_cell *row)
00293 {
00294 const metadata_cell *cell = row + 5;
00295 if (cell->type != METADATA_INT64)
00296 {
00297 if (cell->type != METADATA_NULL) {
00298 ERRORPRINTF("illegal cell type [%d] for filedate", cell->type);
00299 }
00300 return 0;
00301 }
00302 gint64 i64 = cell->value.v_int64;
00303 g_assert(i64 >= 0);
00304 return i64;
00305 }
00306
00307
00308 static const char* get_row_title(const metadata_cell *row)
00309 {
00310 const metadata_cell *cell = row + 6;
00311 if (cell->type != METADATA_TEXT) {
00312 if (cell->type != METADATA_NULL) {
00313 ERRORPRINTF("illegal cell type [%d] for title", cell->type);
00314 }
00315 return NULL;
00316 }
00317 return cell->value.v_text->str;
00318 }
00319
00320
00321 static const char* get_row_author(const metadata_cell *row)
00322 {
00323 const metadata_cell *cell = row + 7;
00324 if (cell->type != METADATA_TEXT) {
00325 if (cell->type != METADATA_NULL) {
00326 ERRORPRINTF("illegal cell type [%d] for author", cell->type);
00327 }
00328 return NULL;
00329 }
00330 return cell->value.v_text->str;
00331 }
00332
00333
00334 static const guchar* get_row_thumbnail(const metadata_cell *row, int* size)
00335 {
00336 const metadata_cell *cell = row + 8;
00337 if (cell->type != METADATA_BLOB) {
00338 if (cell->type != METADATA_NULL) {
00339 ERRORPRINTF("illegal cell type [%d] for thumbnail", cell->type);
00340 }
00341 *size = 0;
00342 return NULL;
00343 }
00344 *size = cell->value.v_blob.len;
00345 return (guchar*)cell->value.v_blob.data;
00346 }
00347
00348
00349 static int get_thumbnail_column()
00350 {
00351 switch (g_thumbnail_size) {
00352 case MODTHUMB_MINI:
00353 return COL_THUMB_MINI;
00354 case MODTHUMB_SMALL:
00355 return COL_THUMB_SMALL;
00356 case MODTHUMB_MEDIUM:
00357 return COL_THUMB_MEDIUM;
00358 case MODTHUMB_LARGE:
00359 return COL_THUMB_LARGE;
00360 default:
00361 ERRORPRINTF("unknown g_thumbnail_size [%d]", g_thumbnail_size);
00362 return -1;
00363 }
00364 }
00365
00366
00367 static int create_query()
00368 {
00369 int thumbcolumn = get_thumbnail_column();
00370 if (thumbcolumn == -1) return ER_FAIL;
00371
00372
00373 int rc= db_query_create(COL_FILENAME,
00374 COL_DIRECTORY_PATH,
00375 COL_IS_DIRECTORY,
00376 COL_FILETYPE,
00377 COL_FILESIZE,
00378 COL_FILETIME_MODIFIED,
00379 COL_TITLE,
00380 COL_AUTHOR,
00381 thumbcolumn,
00382 -1);
00383 if (rc != ER_OK) ERRORPRINTF("error creating query");
00384 return rc;
00385 }
00386
00387
00388 static time_t get_last_modified()
00389 {
00390 const gchar* mountpoint = ipc_get_media();
00391 if (mountpoint == NULL) return 0;
00392
00393 char database_file[256];
00394 sprintf(database_file, "%s/%s", mountpoint, ERMETADB_GLOBAL_DATABASE_FILE);
00395
00396 struct stat statbuf;
00397 stat(database_file, &statbuf);
00398 time_t date_modified = statbuf.st_mtime;
00399 return date_modified;
00400 }
00401
00402
00403 static gboolean is_database_changed()
00404 {
00405 return g_last_modified != get_last_modified();
00406 }
00407
00408
00409
00410 static void load_dir_from_metadb()
00411 {
00412 LOGPRINTF("%s() thumbsize=%d", __func__, g_thumbnail_size);
00413
00414 #if (TIMING_ON)
00415 struct timeval t1, t2;
00416 gettimeofday(&t1, NULL);
00417 #endif
00418
00419 if (g_current_dir == NULL) goto out;
00420
00421
00422 if (g_values) metadata_table_free(g_values);
00423 g_values = NULL;
00424 g_total_items = 0;
00425 g_item_offset = 0;
00426 clear_toggled_list();
00427 bzero(g_alpha_list, sizeof(g_alpha_list));
00428
00429 if (filemodel_current_is_desktop()) goto out;
00430
00431 g_last_modified = get_last_modified();
00432
00433 int rc = create_query();
00434 if (rc != ER_OK) goto out;
00435
00436 switch (g_viewmode2) {
00437 case DESKTOP_VIEW:
00438
00439 break;
00440 case SETTINGS_VIEW:
00441
00442 rc = db_query_execute(g_sort_order,
00443 g_is_sort_asc,
00444 &g_values,
00445 NULL);
00446 break;
00447 case BOOKS_VIEW:
00448 case NEWS_VIEW:
00449 case IMAGES_VIEW:
00450 case PERSONAL_VIEW:
00451 case HELP_VIEW:
00452 case NOTES_VIEW:
00453
00454 g_assert(g_viewmodes[g_viewmode2].tag_filter);
00455 rc = db_query_execute(g_sort_order,
00456 g_is_sort_asc,
00457 &g_values,
00458 g_viewmodes[g_viewmode2].tag_filter);
00459 break;
00460 case DIR_VIEW:
00461
00462 rc = db_query_execute_path_filter(g_sort_order,
00463 g_is_sort_asc,
00464 &g_values,
00465 g_current_dir,
00466 TRUE);
00467 break;
00468 case SHORTCUT_VIEW:
00469
00470 rc = db_query_execute_path_filter(g_sort_order,
00471 g_is_sort_asc,
00472 &g_values,
00473 g_current_dir,
00474 FALSE);
00475 break;
00476 case RECENT_VIEW:
00477 rc = db_query_execute_recent(&g_values, NUM_RECENT_ITEMS);
00478 break;
00479 case SEARCH_VIEW:
00480
00481 rc = db_query_execute_search_filter(g_sort_order,
00482 g_is_sort_asc,
00483 &g_values,
00484 g_search_filter);
00485 break;
00486 }
00487
00488 if (rc != ER_OK)
00489 {
00490 ERRORPRINTF("cannot select metadata");
00491 goto out;
00492 }
00493
00494 if (g_values)
00495 {
00496 g_total_items = metadata_table_n_rows(g_values);
00497 update_alpha_list();
00498 }
00499 out:
00500 #if (TIMING_ON)
00501 gettimeofday(&t2, NULL);
00502 float cost = (float) (((t2.tv_sec - t1.tv_sec) * 1000 * 1000) + (t2.tv_usec - t1.tv_usec));
00503 printf("%s() items=%d duration=%4.1lf ms\n", __func__, g_total_items, cost/1000);
00504 #endif
00505 return;
00506 }
00507
00508
00509 static void set_sortorder(ctb_sort_order_t sort_order)
00510 {
00511 if (g_sort_order == sort_order) return;
00512
00513 static const gboolean is_sort_ascending[N_CTB_SORT_ORDER] =
00514 {
00515 [CTB_SORT_BY_NAME] = TRUE,
00516 [CTB_SORT_BY_TYPE] = TRUE,
00517 [CTB_SORT_BY_SIZE] = FALSE,
00518 [CTB_SORT_BY_DATE_ADDED] = FALSE,
00519 [CTB_SORT_BY_DATE_READ] = FALSE,
00520 [CTB_SORT_BY_AUTHOR] = TRUE,
00521 };
00522
00523 g_sort_order = sort_order;
00524 g_is_sort_asc = is_sort_ascending[sort_order];
00525 menu_select_sort_order(sort_order);
00526 g_subtitle = gettext (order_names[sort_order]);
00527 }
00528
00529
00530 gboolean filemodel_set_sortorder (ctb_sort_order_t sort_order,
00531 const gchar* cursor_item,
00532 gboolean updateScreen)
00533 {
00534 if (g_sort_order == sort_order) return FALSE;
00535
00536 g_assert(!g_viewmodes[g_viewmode2].fixed_order);
00537 g_viewmodes[g_viewmode2].order = sort_order;
00538 set_sortorder(sort_order);
00539
00540 if (updateScreen) {
00541 load_dir_from_metadb();
00542 if (g_values) scroll_to_filename(cursor_item);
00543 load_items_in_model();
00544 }
00545 return TRUE;
00546 }
00547
00548
00549 gboolean filemodel_show_alphabar() {
00550
00551 if (g_viewmode2 == DESKTOP_VIEW || g_viewmode2 == SETTINGS_VIEW) return FALSE;
00552
00553
00554 if (g_sort_order == CTB_SORT_BY_NAME || g_sort_order == CTB_SORT_BY_AUTHOR) {
00555 return TRUE;
00556 }
00557 return FALSE;
00558 }
00559
00560
00561 gboolean filemodel_has_searchbutton()
00562 {
00563 if (g_viewmode2 == DESKTOP_VIEW || g_viewmode2 == SETTINGS_VIEW) return FALSE;
00564 return TRUE;
00565 }
00566
00567
00568 void filemodel_set_viewmode2(ViewMode newmode)
00569 {
00570 LOGPRINTF("viewmode %d -> %d", g_viewmode2, newmode);
00571 if (g_viewmode2 != newmode) {
00572 g_viewmode2 = newmode;
00573 set_sortorder(g_viewmodes[newmode].order);
00574 const char* category = NULL;
00575 if (newmode != DESKTOP_VIEW) {
00576 category = g_viewmodes[newmode].title;
00577 }
00578 menu_set_category(category);
00579 }
00580 }
00581
00582
00583 void filemodel_set_search_filter(const gchar* search_string)
00584 {
00585 g_free(g_search_filter);
00586 g_search_filter = NULL;
00587 if (search_string == NULL || strcmp(search_string, "") == 0) return;
00588 g_search_filter = g_strdup(search_string);
00589 }
00590
00591
00592 const gchar* filemodel_get_title()
00593 {
00594 return _(g_viewmodes[g_viewmode2].title);
00595 }
00596
00597
00598 const gchar* filemodel_get_subtitle()
00599 {
00600 if (g_viewmodes[g_viewmode2].fixed_order) return "";
00601 else return g_subtitle;
00602 }
00603
00604
00605 static gboolean is_dir_on_media(const char* dir)
00606 {
00607 const char* media = ipc_get_media();
00608 if (!media) return FALSE;
00609
00610 int len = strlen(media);
00611 if (strncmp(dir, media, len) == 0 &&
00612 (dir[len] == '/' || dir[len] == '\0')) return TRUE;
00613 return FALSE;
00614 }
00615
00616
00617 static gboolean filemodel_current_is_media()
00618 {
00619 return is_dir_on_media(g_current_dir);
00620 }
00621
00622
00623 const gchar* filemodel_get_menu_content()
00624 {
00625 if (g_viewmode == DELETE_MODE) return MENU_CONTENT_DELETE_MODE;
00626
00627 if (g_viewmode2 == RECENT_VIEW) return MENU_CONTENT_RECENT_MODE;
00628
00629 if (filemodel_current_is_media()) return MENU_CONTENT_MEDIA;
00630
00631 return MENU_CONTENT;
00632 }
00633
00634
00635 gboolean filemodel_set_viewsize (const int n_items, gboolean updateScreen)
00636 {
00637 LOGPRINTF("items=%d->%d updateScreen=%d", g_items_per_page, n_items, updateScreen);
00638 g_return_val_if_fail(n_items > 0 && n_items < 100, FALSE);
00639 if (n_items == g_items_per_page) return FALSE;
00640
00641 g_items_per_page = n_items;
00642
00643
00644 int desktop_page = g_desktop_offset / g_items_per_page;
00645 g_desktop_offset = desktop_page * g_items_per_page;
00646
00647
00648 int page = g_item_offset / g_items_per_page;
00649 g_item_offset = page * g_items_per_page;
00650
00651 if (updateScreen) {
00652 load_items_in_model();
00653 }
00654 return TRUE;
00655 }
00656
00657
00658 void filemodel_set_viewmode(ctb_viewmodes_t newmode, gboolean updateScreen)
00659 {
00660 LOGPRINTF("mode: %d->%d update=%d", g_viewmode, newmode, updateScreen);
00661 g_viewmode = newmode;
00662 clear_toggled_list();
00663 if (updateScreen) {
00664 load_items_in_model();
00665 }
00666 menu_update_view_mode(g_viewmode);
00667 ipc_menu_set_pagecounter(g_curpage, g_numpages, g_boundary_check);
00668 }
00669
00670
00671 void filemodel_set_thumbsize(const filemodel_thumbsize_t thumb_size, gboolean reload)
00672 {
00673 LOGPRINTF("thumb_size [%d]", thumb_size);
00674
00675 if (thumb_size == g_thumbnail_size) return;
00676
00677 g_thumbnail_size = thumb_size;
00678 if (reload) load_dir_from_metadb();
00679
00680 gtk_list_store_clear(g_filestore);
00681 }
00682
00683
00684
00685
00686 static int num_items_per_page()
00687 {
00688 int num_per_page = g_items_per_page;
00689 num_per_page -= num_specials_per_page();
00690 if (num_per_page <= 0) num_per_page = 1;
00691 return num_per_page;
00692 }
00693
00694
00695 gboolean filemodel_has_prev_page()
00696 {
00697 if (filemodel_current_is_desktop()) return (g_desktop_offset > 0);
00698 else return (g_item_offset > 0);
00699 }
00700
00701
00702 gboolean filemodel_has_next_page()
00703 {
00704 return g_has_next_page;
00705 }
00706
00707
00708 void filemodel_page_previous()
00709 {
00710 if (filemodel_current_is_desktop()) {
00711 if (g_desktop_offset > 0) {
00712 g_desktop_offset -= g_items_per_page;
00713 if (g_desktop_offset < 0) g_desktop_offset = 0;
00714 load_items_in_model();
00715 }
00716 } else {
00717 if (g_item_offset > 0) {
00718 g_item_offset -= num_items_per_page();
00719 if (g_item_offset < 0) g_item_offset = 0;
00720 load_items_in_model();
00721 }
00722 }
00723 }
00724
00725
00726 void filemodel_page_next()
00727 {
00728 if (g_has_next_page)
00729 {
00730 LOGPRINTF("entry: old offset [%d] page size [%d]", g_item_offset, g_items_per_page);
00731 if (filemodel_current_is_desktop()) {
00732 g_desktop_offset += g_items_per_page;
00733 g_assert(g_desktop_offset < g_desktop_items);
00734 } else {
00735 g_item_offset += num_items_per_page();
00736 g_assert(g_item_offset < g_total_items);
00737 }
00738 load_items_in_model();
00739 }
00740 }
00741
00742
00743 void filemodel_update_pagecounter()
00744 {
00745 ipc_menu_set_pagecounter(g_curpage, g_numpages, g_boundary_check);
00746 }
00747
00748
00749 static void scroll_to_filename(const gchar *filename)
00750 {
00751 LOGPRINTF("filename=%s", filename);
00752 gint item_idx = 0;
00753
00754 if (g_values && filename && *filename)
00755 {
00756 int row;
00757 int columns = g_values->n_columns;
00758 const metadata_cell *cell = (const metadata_cell*) (g_values->cell_data->data);
00759 for (row = 0; row < g_total_items; row++) {
00760 const gchar* name = get_row_filename(cell);
00761 if (strcmp( filename, name) == 0) {
00762 item_idx = row;
00763 break;
00764 }
00765 cell += columns;
00766 }
00767 }
00768
00769 int num_per_page = num_items_per_page();
00770 int page = item_idx / num_per_page;
00771 g_item_offset = page * num_per_page;
00772 }
00773
00774
00775 static const gchar* get_sorted_name(const metadata_cell* row)
00776 {
00777 const gchar* name = NULL;
00778 if (g_sort_order == CTB_SORT_BY_NAME) {
00779 if (g_viewmode2 == DIR_VIEW) {
00780 name = get_row_filename(row);
00781 } else {
00782 name = get_row_title(row);
00783 if (name == NULL) name = get_row_filename(row);
00784 }
00785 } else if (g_sort_order == CTB_SORT_BY_AUTHOR) {
00786 name = get_row_author(row);
00787 }
00788 return name;
00789 }
00790
00791
00792 static unsigned int alpha2index(char alpha)
00793 {
00794 if (isalpha(alpha)) {
00795 int letter = toupper(alpha);
00796 return (1 + letter - 'A');
00797 } else {
00798 return 0;
00799 }
00800 }
00801
00802
00803 int filemodel_scroll_to_letter(gchar letter, gboolean jump_to_dir, gboolean* same_page)
00804 {
00805 g_assert(g_values);
00806 gint item_idx = 0;
00807 gboolean found = FALSE;
00808
00809 gboolean first_ok = TRUE;
00810 int index = alpha2index(letter);
00811 if (g_alpha_list[index] == (ALPHA_HAS_DIR|ALPHA_HAS_FILE)) first_ok = FALSE;
00812
00813 int row;
00814 const metadata_cell *cell = (const metadata_cell*) (g_values->cell_data->data);
00815 for (row = 0; row < g_total_items; row++) {
00816 const gchar* name = get_sorted_name(cell);
00817 if (name) {
00818 char current = name[0];
00819 if (current == letter || current == tolower(letter) ||
00820 (letter == '#' && !isalpha(current))) {
00821
00822 if (first_ok || jump_to_dir == get_row_is_directory(cell)) {
00823 item_idx = row;
00824 found = TRUE;
00825 break;
00826 }
00827 }
00828 }
00829 cell += g_values->n_columns;
00830 }
00831
00832 int num_per_page = num_items_per_page();
00833 if (item_idx >= g_item_offset && item_idx < (g_item_offset + num_per_page)) {
00834 *same_page = TRUE;
00835 } else {
00836 *same_page = FALSE;
00837 }
00838
00839 int page = item_idx / num_per_page;
00840 g_item_offset = page * num_per_page;
00841
00842 if (found) {
00843 item_idx = item_idx % num_per_page;
00844 item_idx += num_specials_per_page();
00845 } else {
00846
00847 item_idx = -1;
00848 }
00849 if (!*same_page) load_items_in_model();
00850 return item_idx;
00851 }
00852
00853
00854 int filemodel_get_first_alpha_index()
00855 {
00856 if (g_total_items == 0) return -1;
00857 g_assert(g_values);
00858
00859 const metadata_cell *cell = (const metadata_cell*) (g_values->cell_data->data);
00860 cell += (g_item_offset * g_values->n_columns);
00861 const gchar* name = get_sorted_name(cell);
00862 if (name == NULL) return -1;
00863 return alpha2index(name[0]);
00864 }
00865
00866
00867 void filemodel_scroll_to_filename (const gchar *filename)
00868 {
00869 scroll_to_filename(filename);
00870 load_items_in_model();
00871 }
00872
00873
00874 int filemodel_get_display_index(const gchar *filename)
00875 {
00876 if (!filename || !*filename) return 0;
00877
00878
00879 if (filemodel_current_is_desktop()) {
00880 int index = 0;
00881 GSList *iter = desktop_names;
00882 while (iter) {
00883 if (strcmp(filename, (const char*)iter->data) == 0) return index;
00884 index++;
00885 iter = g_slist_next(iter);
00886 }
00887 }
00888 else if (g_values)
00889 {
00890 int num_per_page = num_items_per_page();
00891 int columns = g_values->n_columns;
00892 const metadata_cell *cell = (const metadata_cell*) (g_values->cell_data->data);
00893
00894 cell += (g_item_offset * g_values->n_columns);
00895
00896 int row;
00897 for (row=g_item_offset; row < (g_item_offset + num_per_page) && row < g_total_items ; row++)
00898 {
00899 g_assert(cell->type == METADATA_TEXT);
00900 if (strcmp( filename, cell->value.v_text->str) == 0) {
00901 int item_idx = row - g_item_offset;
00902 item_idx += num_specials_per_page();
00903 return item_idx;
00904 break;
00905 }
00906 cell += columns;
00907 }
00908 }
00909
00910 return 0;
00911 }
00912
00913
00914
00915
00916 static int filemodel_chdir(const gchar *dir, const gchar *cursor_item)
00917 {
00918 LOGPRINTF("dir=%s cursor=%s", dir, cursor_item ? cursor_item : "NULL");
00919 g_assert(dir && *dir);
00920
00921 int ret = ER_OK;
00922 if (filemodel_current_is_desktop()) {
00923 if (ipc_get_media() == NULL) close_database();
00924
00925 } else {
00926 if (g_viewmode2 == SETTINGS_VIEW) {
00927 ret = open_global_database(dir);
00928 } else {
00929 const char* card = ipc_get_media();
00930 ret = open_global_database(card);
00931 }
00932 }
00933 if (ret != ER_OK)
00934 {
00935 ERRORPRINTF("cannot synchronise database, keeping model unchanged");
00936 return ER_FAIL;
00937 }
00938
00939 g_free(g_current_dir);
00940 g_current_dir = g_strdup(dir);
00941 menu_set_current_is_media(filemodel_current_is_media());
00942 load_dir_from_metadb();
00943 if (g_values) scroll_to_filename(cursor_item);
00944 load_items_in_model();
00945
00946 return ER_OK;
00947 }
00948
00949
00950 int filemodel_chdir_desktop()
00951 {
00952 clear_dir_stack();
00953 g_desktop_offset = 0;
00954 filemodel_set_viewmode2(DESKTOP_VIEW);
00955 return filemodel_chdir(DIR_DESKTOP_INTERNAL, NULL);
00956 }
00957
00958
00959 static void free_stack_entry(stack_entry_t *entry)
00960 {
00961 g_assert(entry);
00962 g_free(entry->parent_dir);
00963 g_free(entry->last_item);
00964 g_free(entry);
00965 }
00966
00967
00968 static stack_entry_t* create_stack_entry(const gchar* parent, const gchar* item)
00969 {
00970 stack_entry_t *entry = g_new0(stack_entry_t, 1);
00971 entry->parent_dir = g_strdup(parent);
00972 entry->last_item = g_strdup(item);
00973 return entry;
00974 }
00975
00976
00977 static void clear_dir_stack()
00978 {
00979 GList *iter = g_dir_stack;
00980 while (iter) {
00981 free_stack_entry(iter->data);
00982 iter = g_list_next(iter);
00983 }
00984 g_list_free(g_dir_stack);
00985 g_dir_stack = NULL;
00986 }
00987
00988
00989 int filemodel_chdir_down(const gchar *dir, const gchar *last_item)
00990 {
00991 LOGPRINTF("dir=%s last_item=%s", dir, last_item);
00992 g_dir_stack = g_list_append(g_dir_stack, create_stack_entry(g_current_dir, last_item));
00993
00994 filemodel_chdir(dir, NULL);
00995 return 0;
00996 }
00997
00998
00999 gchar *filemodel_chdir_up()
01000 {
01001 LOGPRINTF("");
01002 g_assert(g_dir_stack);
01003 GList* last = g_list_last(g_dir_stack);
01004 stack_entry_t *entry = (stack_entry_t*)last->data;
01005 g_dir_stack = g_list_delete_link(g_dir_stack, last);
01006
01007 if (g_dir_stack)
01008 {
01009
01010 filemodel_chdir(entry->parent_dir, entry->last_item);
01011 }
01012 else
01013 {
01014
01015 filemodel_set_viewmode2(DESKTOP_VIEW);
01016 filemodel_chdir(DIR_DESKTOP_INTERNAL, NULL);
01017 }
01018 gchar* last_item = g_strdup(entry->last_item);
01019 free_stack_entry(entry);
01020
01021 return last_item;
01022 }
01023
01024
01025 gboolean filemodel_resync(gboolean force_reload)
01026 {
01027 if (!force_reload && !is_database_changed()) return FALSE;
01028
01029 if (filemodel_current_is_desktop()) {
01030 if (g_desktop_items <= g_items_per_page) g_desktop_offset = 0;
01031 }
01032 int old_offset = g_item_offset;
01033 load_dir_from_metadb();
01034
01035
01036 g_item_offset = old_offset;
01037 int num_per_page = num_items_per_page();
01038 while (g_item_offset >= g_total_items) {
01039 g_item_offset -= num_per_page;
01040 }
01041 if (g_item_offset < 0) g_item_offset = 0;
01042 return TRUE;
01043 }
01044
01045
01046 static GdkPixbuf* get_thumbnail_from_data(const guchar* data, int size, const gchar* filename)
01047 {
01048
01049 GdkPixbufLoader *thumb_ldr = gdk_pixbuf_loader_new_with_type(THUMBNAIL_IMAGE_TYPE, NULL);
01050 g_assert(thumb_ldr);
01051 GdkPixbuf* thumbnail = NULL;
01052
01053 GError *err = NULL;
01054 gboolean ok = gdk_pixbuf_loader_write(thumb_ldr, data, size, &err);
01055 if (!ok)
01056 {
01057 ERRORPRINTF("cannot load thumbnail for file [%s] - [%s]", filename, err->message);
01058 goto unref;
01059 }
01060
01061 ok = gdk_pixbuf_loader_close(thumb_ldr, &err);
01062 if (!ok)
01063 {
01064 ERRORPRINTF("cannot close thumbnail for file [%s] - [%s]", filename, err->message);
01065 goto unref;
01066 }
01067
01068
01069 thumbnail = gdk_pixbuf_loader_get_pixbuf(thumb_ldr);
01070 if (thumbnail) {
01071
01072 g_object_ref(thumbnail);
01073 } else {
01074 ERRORPRINTF("cannot get thumbnail pixbuf for file [%s]", filename);
01075 }
01076 unref:
01077 g_clear_error(&err);
01078 g_object_unref(thumb_ldr);
01079 return thumbnail;
01080 }
01081
01082
01083 gboolean filemodel_current_is_desktop()
01084 {
01085 return (g_dir_stack == NULL);
01086 }
01087
01088
01089 gboolean filemodel_window_is_on_top()
01090 {
01091 return g_window_is_on_top;
01092 }
01093
01094
01095 void filemodel_set_window_is_on_top(gboolean is_on_top )
01096 {
01097 g_window_is_on_top = is_on_top;
01098 }
01099
01100
01101 const gchar* filemodel_get_current_dir()
01102 {
01103 return g_current_dir;
01104 }
01105
01106
01107 int filemodel_get_dir_depth()
01108 {
01109 int depth = 0;
01110 if (g_dir_stack != NULL)
01111 {
01112 depth = g_list_length(g_dir_stack);
01113 }
01114 return depth;
01115 }
01116
01117
01118 static void update_alpha_list()
01119 {
01120 bzero(g_alpha_list, sizeof(g_alpha_list));
01121
01122 g_assert(g_values);
01123
01124 if (g_sort_order != CTB_SORT_BY_NAME && g_sort_order != CTB_SORT_BY_AUTHOR) return;
01125
01126 const metadata_cell *cell = (const metadata_cell*) (g_values->cell_data->data);
01127
01128 int row;
01129 for (row=0; row<g_total_items; row++) {
01130 const gchar* name = get_sorted_name(cell);
01131 if (name != NULL) {
01132 int index = alpha2index(name[0]);
01133 gboolean is_dir = get_row_is_directory(cell);
01134 g_alpha_list[index] |= (is_dir ? ALPHA_HAS_DIR : ALPHA_HAS_FILE);
01135 }
01136
01137 cell += g_values->n_columns;
01138 }
01139 }
01140
01141
01142 const gchar* filemodel_get_alpha_list()
01143 {
01144 return g_alpha_list;
01145 }
01146
01147
01148 static int is_row_toggled(int row, const gchar* filename, const gchar* dirpath)
01149 {
01150 if (g_viewmode == DELETE_MODE) {
01151
01152 if (!is_delete_allowed(filename, dirpath)) return -1;
01153
01154
01155 GSList *iter = toggled_list;
01156 while (iter) {
01157 if (row == (int)iter->data) return 1;
01158 iter = g_slist_next(iter);
01159 }
01160 }
01161 return 0;
01162 }
01163
01164
01165 static void clear_toggled_list()
01166 {
01167 g_slist_free(toggled_list);
01168 toggled_list = NULL;
01169 }
01170
01171
01172 static gint compare_toggled_entries(gconstpointer left, gconstpointer right)
01173 {
01174 return ((int)left > (int)right);
01175 }
01176
01177
01178 void filemodel_toggle_entry(int index, int state, GtkTreeIter *iter)
01179 {
01180 index -= num_specials_per_page();
01181 int item_index = g_item_offset + index;
01182
01183 if (state == 0) {
01184 toggled_list = g_slist_remove(toggled_list, (int*)item_index);
01185 } else {
01186 toggled_list = g_slist_prepend(toggled_list, (int*)item_index);
01187 }
01188
01189 GtkTreeModel *model = GTK_TREE_MODEL(g_filestore);
01190
01191
01192 if (g_viewmode == DELETE_MODE && g_thumbnail_size == MODTHUMB_MEDIUM)
01193 {
01194 const metadata_cell *cell = (const metadata_cell*) (g_values->cell_data->data);
01195 cell += (item_index * g_values->n_columns);
01196 GdkPixbuf *thumbnail = get_thumbnail(cell);
01197 GdkPixbuf *thumbnail_delete = create_delete_overlay(thumbnail, state);
01198
01199 gtk_list_store_set (GTK_LIST_STORE(model), iter, MODCOL_THUMBNAIL, thumbnail_delete, -1);
01200 g_object_unref(thumbnail);
01201 g_object_unref(thumbnail_delete);
01202 }
01203 gtk_list_store_set (GTK_LIST_STORE(model), iter, MODCOL_TOGGLED, state, -1);
01204 }
01205
01206
01207 static void delete_entry_at_offset(int offset)
01208 {
01209 g_assert(offset < g_total_items);
01210 const metadata_cell *cell = (const metadata_cell*) (g_values->cell_data->data);
01211
01212 cell += (offset * g_values->n_columns);
01213
01214 const char* filename = get_row_filename(cell);
01215 const char *dirpath = get_row_dirpath(cell);
01216 gboolean is_directory = get_row_is_directory(cell);
01217 const char *filetype = get_row_filetype(cell);
01218
01219
01220 #if MACHINE_IS_DR800S || MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
01221 if (g_last_read &&
01222 strcmp(filename, g_last_read->filename->str) == 0 &&
01223 strcmp(dirpath, g_last_read->directory_path->str) == 0)
01224 {
01225 clear_last_read();
01226 }
01227 #endif
01228
01229 filelist_entry_t *entry = filelist_entry_new();
01230 entry->filename = g_string_new(filename);
01231 entry->filename_display = NULL;
01232 entry->filetype = g_string_new(filetype);
01233 entry->directory_path = g_string_new(dirpath);
01234 entry->is_directory = is_directory;
01235 delete_item(entry);
01236 filelist_entry_free(entry);
01237 }
01238
01239
01240 void filemodel_delete_toggled()
01241 {
01242 if (toggled_list) {
01243 toggled_list = g_slist_sort(toggled_list, compare_toggled_entries);
01244 GSList *iter = toggled_list;
01245 while (iter) {
01246 int item_offset = (int)iter->data;
01247 delete_entry_at_offset(item_offset);
01248 iter = g_slist_next(iter);
01249 }
01250 clear_toggled_list();
01251 filemodel_resync(FALSE);
01252 }
01253 }
01254
01255
01256 int filemodel_num_toggled()
01257 {
01258 int count = 0;
01259 GSList *iter = toggled_list;
01260 while (iter) {
01261 count++;
01262 iter = g_slist_next(iter);
01263 }
01264 return count;
01265 }
01266
01267
01268 void filemodel_set_delete_text(const gchar* text)
01269 {
01270 if (g_delete_text != NULL && strcmp(g_delete_text, text) == 0) return;
01271 g_free(g_delete_text);
01272 g_delete_text = g_strdup(text);
01273 if (g_viewmode == DELETE_MODE) {
01274 GtkTreeIter first;
01275 GtkTreeModel *model = GTK_TREE_MODEL(g_filestore);
01276 gboolean valid = gtk_tree_model_get_iter_first(model, &first);
01277 if (valid) {
01278 gtk_list_store_set (GTK_LIST_STORE(model), &first,
01279 MODCOL_TITLE, g_delete_text, -1);
01280 }
01281 }
01282 }
01283
01284
01285 static gboolean is_delete_allowed(const gchar* filename, const gchar* dirpath) {
01286
01287 if (strcmp(dirpath, DIR_LIBRARY) == 0 && strcmp(filename, "System") == 0) return FALSE;
01288
01289 const gchar *dir = dirpath;
01290 if (strcmp(dirpath, ".") == 0) dir = g_current_dir;
01291 char real_dir[PATH_MAX];
01292 char *cp = realpath(dir, real_dir);
01293 if (cp == real_dir) {
01294
01295 if (strcmp(real_dir, DIR_DESKTOP_INTERNAL) == 0) return FALSE;
01296
01297
01298 if (!is_dir_on_media(real_dir)) return FALSE;
01299 }
01300
01301 return TRUE;
01302 }
01303
01304
01305 static void add_previous_dir(const gchar* title, const gchar* subtitle, const gchar* iconname)
01306 {
01307 gtk_list_store_insert_with_values(
01308 g_filestore,
01309 NULL,
01310 g_items_per_page,
01311 MODCOL_FILENAME, "..",
01312 MODCOL_TITLE, title,
01313 MODCOL_FILETYPE, SPECIAL_ITEM_NAME,
01314 MODCOL_FILETYPE_DISPLAY, "",
01315 MODCOL_DIRECTORY_PATH, ".",
01316 MODCOL_IS_DIRECTORY, TRUE,
01317 MODCOL_FILESIZE, "",
01318 MODCOL_FILEDATE, "",
01319 MODCOL_SUBTITLE, subtitle,
01320 MODCOL_THUMBNAIL, get_icon_from_file(iconname, g_thumbnail_size),
01321 MODCOL_TOGGLED, -1,
01322 -1 );
01323 }
01324
01325
01326 static int num_browse_mode_specials()
01327 {
01328 switch (g_viewmode2) {
01329 case DESKTOP_VIEW:
01330 return 0;
01331 case SETTINGS_VIEW:
01332 case BOOKS_VIEW:
01333 case NEWS_VIEW:
01334 case IMAGES_VIEW:
01335 case PERSONAL_VIEW:
01336 case HELP_VIEW:
01337 case SEARCH_VIEW:
01338 case RECENT_VIEW:
01339 return 1;
01340 case NOTES_VIEW:
01341 return 2;
01342 case DIR_VIEW:
01343 case SHORTCUT_VIEW:
01344 return 1;
01345 }
01346 return 0;
01347 }
01348
01349
01350 static void add_browse_mode_specials()
01351 {
01352 switch (g_viewmode2) {
01353 case DESKTOP_VIEW:
01354
01355 break;
01356 case SETTINGS_VIEW:
01357 case BOOKS_VIEW:
01358 case NEWS_VIEW:
01359 case IMAGES_VIEW:
01360 case PERSONAL_VIEW:
01361 case HELP_VIEW:
01362 case SEARCH_VIEW:
01363 case RECENT_VIEW:
01364 add_previous_dir(_("to Home"), _("Return to the Home screen"), "back");
01365 break;
01366 case NOTES_VIEW:
01367 add_previous_dir(_("to Home"), _("Return to the Home screen"), "back");
01368 gtk_list_store_insert_with_values(
01369 g_filestore,
01370 NULL,
01371 g_items_per_page,
01372
01373 MODCOL_FILENAME, "new",
01374 MODCOL_TITLE, _("New Note"),
01375 MODCOL_FILETYPE, "note",
01376 MODCOL_FILETYPE_DISPLAY, "",
01377 MODCOL_DIRECTORY_PATH, "",
01378 MODCOL_IS_DIRECTORY, FALSE,
01379 MODCOL_FILESIZE, "",
01380 MODCOL_FILEDATE, "",
01381 MODCOL_SUBTITLE, _("Open a new notepad to write on"),
01382 MODCOL_THUMBNAIL, get_icon_from_file("new-note", g_thumbnail_size),
01383 MODCOL_TOGGLED, -1,
01384 -1 );
01385 break;
01386 case DIR_VIEW:
01387 case SHORTCUT_VIEW:
01388 add_previous_dir(_("Up a Level"), "", "parent-dir");
01389 break;
01390 }
01391 }
01392
01393
01394 static void add_delete_mode_specials()
01395 {
01396 gtk_list_store_insert_with_values(
01397 g_filestore,
01398 NULL,
01399 g_items_per_page,
01400 MODCOL_FILENAME, "DELETE-ACTION",
01401 MODCOL_TITLE, g_delete_text,
01402 MODCOL_FILETYPE, "",
01403 MODCOL_FILETYPE_DISPLAY, "",
01404 MODCOL_DIRECTORY_PATH, "",
01405 MODCOL_IS_DIRECTORY, FALSE,
01406 MODCOL_FILESIZE, "",
01407 MODCOL_FILEDATE, "",
01408 MODCOL_SUBTITLE, "",
01409 MODCOL_THUMBNAIL, get_icon_from_file("delete-action", g_thumbnail_size),
01410 MODCOL_TOGGLED, -1,
01411 -1 );
01412 }
01413
01414
01415
01416 static int num_specials_per_page()
01417 {
01418 switch (g_viewmode) {
01419 case BROWSE_MODE:
01420 return num_browse_mode_specials();
01421 case DELETE_MODE:
01422 return 1;
01423 }
01424 return 0;
01425 }
01426
01427
01428 static void add_special_items()
01429 {
01430 switch (g_viewmode) {
01431 case BROWSE_MODE:
01432 add_browse_mode_specials();
01433 break;
01434 case DELETE_MODE:
01435 add_delete_mode_specials();
01436 break;
01437 }
01438 }
01439
01440
01441
01442
01443 static void update_numpages(int items_per_page)
01444 {
01445 LOGPRINTF("items_per_page=%d", items_per_page);
01446 int first = 0;
01447 int total = 0;
01448 if (filemodel_current_is_desktop()) {
01449 first = MIN(g_desktop_offset + 1, g_desktop_items);
01450 total = g_desktop_items;
01451 g_has_next_page = (g_desktop_offset + items_per_page < total);
01452 } else {
01453
01454
01455 if (g_item_offset % items_per_page != 0) {
01456 int offset = g_item_offset % items_per_page;
01457 g_item_offset -= offset;
01458 if (g_item_offset < 0) g_item_offset = 0;
01459 }
01460
01461 first = MIN(g_item_offset + 1, g_total_items);
01462 total = g_total_items;
01463 g_has_next_page = (g_item_offset + items_per_page < total);
01464 }
01465
01466 g_curpage = (first / items_per_page) + 1;
01467 g_numpages = total / items_per_page;
01468 if (total % items_per_page != 0) g_numpages++;
01469 if (g_numpages == 0) g_numpages = 1;
01470
01471 if (filemodel_current_is_desktop() && g_numpages == 1) {
01472 g_curpage = 0;
01473 g_numpages = 0;
01474 }
01475
01476 if (filemodel_window_is_on_top())
01477 {
01478 ipc_menu_set_pagecounter(g_curpage, g_numpages, g_boundary_check);
01479 }
01480 }
01481
01482
01483 static GdkPixbuf* get_thumbnail_for_shortcut(shortcut_t *shortcut,
01484 gboolean is_directory,
01485 const gchar* filetype,
01486 const gchar* filename,
01487 const gchar* dir)
01488 {
01489 GdkPixbuf* thumbnail = NULL;
01490
01491 switch (shortcut->type)
01492 {
01493 case SHORTCUT_TO_FILE:
01494 {
01495
01496 const gchar *ext = g_extension_pointer(shortcut->details.file.filename);
01497 thumbnail = get_icon_from_file_extension( ext,
01498 is_directory,
01499 g_thumbnail_size );
01500 break;
01501 }
01502 case SHORTCUT_TO_FOLDER:
01503 {
01504
01505 char *cp = shortcut->details.folder.directory;
01506 if ( cp
01507 && shortcut->details.folder.filename == NULL )
01508 {
01509 if ( strcmp(cp, DIR_LIBRARY) == 0 )
01510 {
01511
01512 thumbnail = get_icon_library( g_thumbnail_size );
01513 }
01514 else
01515 {
01516 int n = strlen(DIR_STORAGE_MNT);
01517 if ( strncmp(cp, DIR_STORAGE_MNT, n) == 0
01518 && cp[n] == '/' )
01519 {
01520
01521 cp = strchr( cp + n + 1, '/' );
01522 if ( cp == NULL )
01523 {
01524
01525 thumbnail = get_icon_library( g_thumbnail_size );
01526 }
01527 }
01528 }
01529 }
01530
01531
01532 if (thumbnail == NULL)
01533 {
01534 thumbnail = get_icon_from_file_extension( "",
01535 TRUE,
01536 g_thumbnail_size );
01537 }
01538 break;
01539 }
01540 case SHORTCUT_TO_APPLICATION:
01541
01542 thumbnail = get_icon_application( g_thumbnail_size );
01543 break;
01544
01545 case SHORTCUT_TO_WEB_LOCATION:
01546 thumbnail = get_icon_from_file_extension( "html",
01547 FALSE,
01548 g_thumbnail_size );
01549
01550 break;
01551
01552 default:
01553 WARNPRINTF("unknown shortcut type [%d] file [%s]", shortcut->type, filename);
01554
01555
01556 thumbnail = get_icon_from_file_extension( filetype,
01557 is_directory,
01558 g_thumbnail_size );
01559 }
01560
01561
01562 if (thumbnail)
01563 {
01564 if ( strcmp(dir, DIR_DESKTOP_INTERNAL) != 0 )
01565 {
01566 thumbnail = gdk_pixbuf_copy(thumbnail);
01567 apply_icon_overlay_shortcut(g_thumbnail_size, thumbnail);
01568 }
01569 else
01570 {
01571 g_object_ref(thumbnail);
01572 }
01573 }
01574 return thumbnail;
01575 }
01576
01577
01578 static gboolean desktop_item_visible(int index)
01579 {
01580 if (index >= g_desktop_offset &&
01581 index < g_desktop_offset + g_items_per_page) return TRUE;
01582 return FALSE;
01583 }
01584
01585
01586 static void add_desktop_item(int index,
01587 const gchar* filename,
01588 const gchar* title,
01589 const gchar* subtitle,
01590 const gchar* path,
01591 const gchar* iconname)
01592 {
01593 if (!desktop_item_visible(index)) return;
01594 gtk_list_store_insert_with_values(
01595 g_filestore,
01596 NULL,
01597 g_items_per_page,
01598 MODCOL_FILENAME, filename,
01599 MODCOL_TITLE, title,
01600 MODCOL_FILETYPE, SPECIAL_ITEM_NAME,
01601 MODCOL_FILETYPE_DISPLAY, "",
01602 MODCOL_DIRECTORY_PATH, path,
01603 MODCOL_IS_DIRECTORY, TRUE,
01604 MODCOL_FILESIZE, "",
01605 MODCOL_FILEDATE, "",
01606 MODCOL_SUBTITLE, subtitle,
01607 MODCOL_THUMBNAIL, get_icon_from_file(iconname, g_thumbnail_size),
01608 MODCOL_TOGGLED, -1,
01609 -1 );
01610 desktop_names = g_slist_append(desktop_names, g_strdup(filename));
01611 }
01612
01613
01614 #if MACHINE_IS_DR800S || MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
01615 static gboolean add_desktop_last_read_item(int index)
01616 {
01617 if (!g_last_read) return FALSE;
01618
01619 g_assert(g_last_read->filename);
01620 g_assert(g_last_read->filetype);
01621 g_assert(g_last_read->directory_path);
01622 g_assert(g_last_read->filename_display);
01623
01624 if (open_global_database(DIR_LIBRARY) != ER_OK)
01625 {
01626 ERRORPRINTF("cannot open database on card");
01627 return FALSE;
01628 }
01629
01630 int rc = create_query();
01631 if (rc != ER_OK) return FALSE;
01632
01633 if (g_last_read_results) {
01634 metadata_table_free(g_last_read_results);
01635 g_last_read_results = NULL;
01636 }
01637 rc = db_query_get_metadata(g_last_read->filename->str, g_last_read->directory_path->str, &g_last_read_results);
01638 if (rc != ER_OK) {
01639 ERRORPRINTF("cannot get metadata for database");
01640 return FALSE;
01641 }
01642
01643
01644 if (g_last_read_results)
01645 {
01646 if (!desktop_item_visible(index)) return TRUE;
01647
01648 const metadata_cell *cell = (const metadata_cell*) (g_last_read_results->cell_data->data);
01649 const char *title = get_row_title(cell);
01650
01651
01652 int thumbsize = 0;
01653 const guchar* thumbdata = get_row_thumbnail(cell, &thumbsize);
01654 GdkPixbuf *thumbnail = NULL;
01655 if (thumbdata != NULL) {
01656 thumbnail = get_thumbnail_from_data(thumbdata, thumbsize, g_last_read->filename->str);
01657 } else {
01658 thumbnail = get_icon_from_file_extension(g_last_read->filetype->str, FALSE, g_thumbnail_size);
01659 if (thumbnail) g_object_ref(thumbnail);
01660 }
01661
01662 gtk_list_store_insert_with_values(
01663 g_filestore,
01664 NULL,
01665 g_items_per_page,
01666 MODCOL_FILENAME, g_last_read->filename->str,
01667 MODCOL_TITLE, _("Continue Reading"),
01668 MODCOL_FILETYPE, g_last_read->filetype->str,
01669 MODCOL_FILETYPE_DISPLAY, "",
01670 MODCOL_DIRECTORY_PATH, g_last_read->directory_path->str,
01671 MODCOL_IS_DIRECTORY, FALSE,
01672 MODCOL_FILESIZE, "",
01673 MODCOL_FILEDATE, "",
01674 MODCOL_SUBTITLE, title,
01675 MODCOL_THUMBNAIL, thumbnail,
01676 MODCOL_TOGGLED, -1,
01677 -1 );
01678 if (thumbnail) g_object_unref(thumbnail);
01679 desktop_names = g_slist_append(desktop_names, g_strdup(g_last_read->filename->str));
01680 return TRUE;
01681 } else {
01682
01683 clear_last_read();
01684 return FALSE;
01685 }
01686 }
01687 #endif
01688
01689
01690 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
01691 static void add_desktop_store_item(int index)
01692 {
01693 if (!desktop_item_visible(index)) return;
01694
01695 const char* filename = "ebookmall.desktop";
01696 gtk_list_store_insert_with_values(
01697 g_filestore,
01698 NULL,
01699 g_items_per_page,
01700 MODCOL_FILENAME, filename,
01701 MODCOL_TITLE, _("eBook Mall"),
01702 MODCOL_FILETYPE, "desktop",
01703 MODCOL_FILETYPE_DISPLAY, "",
01704 MODCOL_DIRECTORY_PATH, DIR_DESKTOP_TEMPLATE,
01705 MODCOL_IS_DIRECTORY, FALSE,
01706 MODCOL_FILESIZE, "",
01707 MODCOL_FILEDATE, "",
01708 MODCOL_SUBTITLE, _("Browse the eBook Mall for new books and much more"),
01709 MODCOL_THUMBNAIL, get_icon_from_file("shop", g_thumbnail_size),
01710 MODCOL_TOGGLED, -1,
01711 -1 );
01712 desktop_names = g_slist_append(desktop_names, g_strdup(filename));
01713 }
01714 #endif
01715
01716
01717 static void clear_desktop_names()
01718 {
01719 GSList *iter = desktop_names;
01720 while (iter) {
01721 g_free((char*)iter->data);
01722 iter = g_slist_next(iter);
01723 }
01724 g_slist_free(desktop_names);
01725 desktop_names = NULL;
01726 }
01727
01728
01729 static int add_desktop_items()
01730 {
01731 clear_desktop_names();
01732
01733 const gchar* mountpoint = ipc_get_media();
01734
01735 int idx = 0;
01736 #if MACHINE_IS_DR800S || MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
01737 if (add_desktop_last_read_item(idx)) idx++;
01738 #endif
01739 add_desktop_item(idx++, SPECIAL_BOOKS, _("Books"), _("See all the books that have been saved to your library"), mountpoint, "books");
01740 add_desktop_item(idx++, SPECIAL_NEWS, _("News"), _("Read the latest newspapers and other periodicals"), mountpoint, "news");
01741 add_desktop_item(idx++, SPECIAL_IMAGES, _("Images"), _("View your saved pictures and images"), mountpoint, "images");
01742 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
01743 add_desktop_store_item(idx++);
01744 #endif
01745 add_desktop_item(idx++, SPECIAL_PERSONAL, _("Personal Documents"), _("See all the files saved in Personal Documents"), mountpoint, "personal");
01746 char buffer[512];
01747 sprintf(buffer, "%s/%s", mountpoint, DIR_NOTES);
01748 add_desktop_item(idx++, SPECIAL_NOTES, _("Notes"), _("Keep track of your notes with this handy notepad"), buffer, "notes");
01749 add_desktop_item(idx++, SPECIAL_RECENT, _("Recently Added"), _("View the last 15 items added to the device"), mountpoint, "recent");
01750 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
01751 sprintf(buffer, "%s/%s", mountpoint, DIR_SHORTCUTS);
01752 add_desktop_item(idx++, SPECIAL_SHORTCUTS, _("Shortcuts"), _("Shortcuts that you've made to your documents are found here"), buffer, "shortcuts");
01753 #endif
01754 if (filetypes_showdir())
01755 add_desktop_item(idx++, SPECIAL_DIR, _("SD Card"), _("Browse and navigate the folders saved on the SD card"), mountpoint, "sdcard");
01756 add_desktop_item(idx++, SPECIAL_SEARCH, _("Search"), _("Search for books, news items, or images"), mountpoint, "search");
01757 add_desktop_item(idx++, SPECIAL_HELP, _("Help"), _("Learn more about the device and features"), mountpoint, "help");
01758 add_desktop_item(idx++, SPECIAL_SETTINGS, _("Settings"), _("Find and edit the settings used on this device"), "/usr/share/ctb/settings", "settings");
01759 return idx;
01760 }
01761
01762
01763 static GdkPixbuf *get_thumbnail(const metadata_cell *cell)
01764 {
01765 const char *filename = get_row_filename(cell);
01766 gboolean is_directory = get_row_is_directory(cell);
01767 const char *filetype = get_row_filetype(cell);
01768
01769
01770 int thumbsize = 0;
01771 const guchar* thumbdata = get_row_thumbnail(cell, &thumbsize);
01772 GdkPixbuf *thumbnail = NULL;
01773 if (thumbdata != NULL) {
01774 thumbnail = get_thumbnail_from_data(thumbdata, thumbsize, filename);
01775 }
01776
01777
01778 if (thumbnail == NULL && is_shortcut_file_extension(filetype)) {
01779 shortcut_t *shortcut = NULL;
01780 const char *dirpath = get_row_dirpath(cell);
01781 const gchar *dir = dirpath;
01782 if (strcmp(dirpath, ".") == 0) dir = g_current_dir;
01783 parse_shortcut_file(dir, filename, &shortcut);
01784 if (shortcut) {
01785 thumbnail = get_thumbnail_for_shortcut(shortcut, is_directory,
01786 filetype, filename, dir);
01787 shortcut_free(shortcut);
01788 }
01789 }
01790
01791
01792 if (thumbnail == NULL) {
01793 thumbnail = get_icon_from_file_extension(filetype, is_directory,
01794 g_thumbnail_size);
01795 if (thumbnail) g_object_ref(thumbnail);
01796 }
01797
01798 return thumbnail;
01799 }
01800
01801
01802 static GdkPixbuf *create_delete_overlay(const GdkPixbuf* source, gboolean toggled)
01803 {
01804 GdkPixbuf *result = NULL;
01805 if (gdk_pixbuf_get_width(source) != 120 || gdk_pixbuf_get_height(source) != 120) {
01806
01807 GdkPixbuf * empty = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 120, 120);
01808 gdk_pixbuf_fill(empty, 0x00000000);
01809 int x_offset = (120 - gdk_pixbuf_get_width(source)) / 2;
01810 int y_offset = (120 - gdk_pixbuf_get_height(source)) / 2;
01811 gdk_pixbuf_copy_area(source,
01812 0, 0,
01813 gdk_pixbuf_get_width(source),
01814 gdk_pixbuf_get_height(source),
01815 empty,
01816 x_offset, y_offset);
01817 apply_icon_overlay_delete(MODTHUMB_MEDIUM, empty, toggled);
01818 result = empty;
01819 } else {
01820 GdkPixbuf *source_copy = gdk_pixbuf_copy(source);
01821 apply_icon_overlay_delete(MODTHUMB_MEDIUM, source_copy, toggled);
01822 return source_copy;
01823 }
01824 return result;
01825 }
01826
01827
01828 static char* get_title(const shortcut_t *shortcut, const char* title, const char* filename)
01829 {
01830
01831 if (g_viewmode2 == DIR_VIEW) return g_strdup(filename);
01832
01833 if (title && title[0]) return g_strdup(title);
01834
01835 if (shortcut) return g_strdup(shortcut->name);
01836
01837 return g_strdup(filename);
01838 }
01839
01840
01841 static char* get_subtitle(const shortcut_t *shortcut, const char* author)
01842 {
01843 if (!shortcut) {
01844 if (author && author[0]) {
01845
01846
01847 return g_strdup_printf(_("by %s"), author);
01848 } else {
01849 return NULL;
01850 }
01851 }
01852
01853 if (g_viewmode2 == DIR_VIEW) return g_strdup(shortcut->name);
01854
01855 if (shortcut->comment) return g_strdup(shortcut->comment);
01856
01857 if (shortcut->type == SHORTCUT_TO_APPLICATION) return NULL;
01858
01859 if (author) {
01860
01861
01862 return g_strdup_printf(_("shortcut to %s"), author);
01863 }
01864
01865 return NULL;
01866 }
01867
01868
01869
01870
01871 static void load_items_in_model()
01872 {
01873 LOGPRINTF( "total=%d offset=%d items_per_page=%d",
01874 g_total_items, g_item_offset, g_items_per_page);
01875
01876 if (g_values == NULL && g_total_items != 0) return;
01877 if (g_current_dir == NULL) return;
01878
01879 #if (TIMING_ON)
01880 struct timeval t1, t2;
01881 gettimeofday(&t1, NULL);
01882 #endif
01883
01884
01885 gtk_list_store_clear(g_filestore);
01886
01887 if (filemodel_current_is_desktop()) {
01888 const gchar* mountpoint = ipc_get_media();
01889 if (mountpoint == NULL) goto out;
01890 g_desktop_items = add_desktop_items();
01891 if (g_desktop_offset >= g_desktop_items) {
01892
01893 gtk_list_store_clear(g_filestore);
01894 g_desktop_offset = 0;
01895 g_desktop_items = add_desktop_items();
01896 }
01897 update_numpages(g_items_per_page);
01898 goto out;
01899 }
01900
01901 g_assert(g_item_offset <= g_total_items);
01902
01903 int items_per_page = num_items_per_page();
01904 update_numpages(items_per_page);
01905 add_special_items();
01906 if (g_total_items == 0) goto out;
01907
01908
01909 const metadata_cell *cell = (const metadata_cell*) (g_values->cell_data->data);
01910
01911
01912 cell += (g_item_offset * g_values->n_columns);
01913
01914 int row;
01915 for (row=g_item_offset; row < (g_item_offset + items_per_page) && row < g_total_items ; row++)
01916 {
01917 const char *filename = get_row_filename(cell);
01918 const char *dirpath = get_row_dirpath(cell);
01919 gboolean is_directory = get_row_is_directory(cell);
01920 const char *filetype = get_row_filetype(cell);
01921 const char *title = get_row_title(cell);
01922 const char *author = get_row_author(cell);
01923
01924 const char *filetype_display = "";
01925 if (filetype) {
01926 filetype_display = get_type_descr_from_file_extension(filetype, is_directory);
01927 }
01928
01929 gint64 size = get_row_filesize(cell);
01930 gchar *filesize = NULL;
01931 if (!is_directory) filesize = format_size(size);
01932
01933 time_t date = get_row_filedate(cell);
01934 char filedate[100];
01935 filedate[0] = '\0';
01936
01937
01938
01939
01940 strftime(filedate, sizeof(filedate), _("%x %X"), localtime(&date));
01941
01942 gboolean is_shortcut = is_shortcut_file_extension(filetype);
01943
01944 shortcut_t *shortcut = NULL;
01945 if (is_shortcut) {
01946 const gchar *dir = dirpath;
01947 if (strcmp(dirpath, ".") == 0) dir = g_current_dir;
01948 parse_shortcut_file(dir, filename, &shortcut);
01949 }
01950
01951
01952 char *title_display = get_title(shortcut, title, filename);
01953
01954
01955 gchar* subtitle_display = NULL;
01956 if (is_shortcut && shortcut == NULL) {
01957 subtitle_display = g_strdup(_("broken shortcut"));
01958 } else {
01959 #if MACHINE_HAS_ACSM
01960 if (strcmp("acsm", filetype) == 0) {
01961 subtitle_display = g_strdup(_("This file will be downloaded to your device."));
01962 } else
01963 #endif
01964 {
01965 subtitle_display = get_subtitle(shortcut, author);
01966 }
01967 }
01968
01969 shortcut_free(shortcut);
01970
01971 gint toggled = is_row_toggled(row, filename, dirpath);
01972
01973 GdkPixbuf *thumbnail = get_thumbnail(cell);
01974
01975
01976 if (g_viewmode == DELETE_MODE && g_thumbnail_size == MODTHUMB_MEDIUM && toggled != -1)
01977 {
01978 GdkPixbuf *thumbnail_delete = create_delete_overlay(thumbnail, toggled);
01979 g_object_unref(thumbnail);
01980 thumbnail = thumbnail_delete;
01981 }
01982
01983
01984 gtk_list_store_insert_with_values( g_filestore,
01985 NULL,
01986 g_items_per_page,
01987 MODCOL_FILENAME, filename,
01988 MODCOL_TITLE, title_display,
01989 MODCOL_FILETYPE, filetype,
01990 MODCOL_FILETYPE_DISPLAY, filetype_display,
01991 MODCOL_DIRECTORY_PATH, dirpath,
01992 MODCOL_IS_DIRECTORY, is_directory,
01993 MODCOL_FILESIZE, filesize,
01994 MODCOL_FILEDATE, filedate,
01995 MODCOL_SUBTITLE, subtitle_display,
01996 MODCOL_THUMBNAIL, thumbnail,
01997 MODCOL_TOGGLED, toggled,
01998 -1 );
01999
02000 if (thumbnail) g_object_unref(thumbnail);
02001 g_free(filesize);
02002 g_free(title_display);
02003 g_free(subtitle_display);
02004 cell += g_values->n_columns;
02005 }
02006 out:
02007 #if (TIMING_ON)
02008 gettimeofday(&t2, NULL);
02009 float cost = (float) (((t2.tv_sec - t1.tv_sec) * 1000 * 1000) + (t2.tv_usec - t1.tv_usec));
02010 printf("%s() duration=%4.1lf ms\n", __func__, cost/1000);
02011 #endif
02012 return;
02013 }
02014
02015
02016
02017 static gchar* format_size(const gint64 bytes)
02018 {
02019 gchar *size = NULL;
02020 long n_int;
02021 long n_frac;
02022
02023 const int MB = 1024 * 1024;
02024 const int KB = 1024;
02025
02026 if (bytes >= MB)
02027 {
02028 if (bytes >= 10 * MB)
02029 {
02030 n_int = (bytes + (MB / 2)) / MB;
02031 size = g_strdup_printf( "%ld %s",
02032 n_int,
02033 _("MB") );
02034 }
02035 else
02036 {
02037 n_int = bytes / MB;
02038 n_frac = ((bytes % MB) + (MB / 20)) / (MB / 10);
02039 n_frac = MIN(n_frac, 9);
02040 size = g_strdup_printf( "%ld.%ld %s",
02041 n_int,
02042 n_frac,
02043 _("MB") );
02044 }
02045 }
02046 else if (bytes >= KB)
02047 {
02048 if (bytes >= 10 * KB)
02049 {
02050 n_int = (bytes + (KB / 2)) / KB;
02051 size = g_strdup_printf( "%ld %s",
02052 n_int,
02053 _("KB") );
02054 }
02055 else
02056 {
02057 n_int = bytes / KB;
02058 n_frac = ((bytes % KB) + (KB / 20)) / (KB / 10);
02059 n_frac = MIN(n_frac, 9);
02060 size = g_strdup_printf( "%ld.%ld %s",
02061 n_int,
02062 n_frac,
02063 _("KB") );
02064 }
02065 }
02066 else
02067 {
02068 size = g_strdup_printf( "%lld %s",
02069 bytes,
02070 _("B") );
02071 }
02072
02073 return size;
02074 }
02075
02076
02077
02078
02079
02080
02081 filelist_entry_t* iter_to_entry(GtkTreeModel *model, GtkTreeIter *iter)
02082 {
02083 gchar *filename = NULL;
02084 gchar *filename_display = NULL;
02085 gchar *filetype = NULL;
02086 gchar *directory_path = NULL;
02087 gboolean is_directory = FALSE;
02088
02089 gtk_tree_model_get( model, iter, MODCOL_FILENAME, &filename,
02090 MODCOL_TITLE, &filename_display,
02091 MODCOL_FILETYPE, &filetype,
02092 MODCOL_DIRECTORY_PATH, &directory_path,
02093 MODCOL_IS_DIRECTORY, &is_directory,
02094 -1 );
02095
02096 filelist_entry_t *entry = filelist_entry_new();
02097 entry->filename = g_string_new(filename);
02098 entry->filename_display = g_string_new(filename_display);
02099 entry->filetype = g_string_new(filetype);
02100 entry->directory_path = g_string_new(directory_path);
02101 entry->is_directory = is_directory;
02102
02103 g_free(filename);
02104 g_free(filename_display);
02105 g_free(filetype);
02106 g_free(directory_path);
02107
02108 return entry;
02109 }
02110
02111
02112 filelist_entry_t* filelist_entry_new()
02113 {
02114 filelist_entry_t *thiz = g_new0(filelist_entry_t, 1);
02115 g_assert(thiz);
02116 thiz->is_directory = FALSE;
02117
02118 return thiz;
02119 }
02120
02121
02122 void filelist_entry_free(filelist_entry_t *thiz)
02123 {
02124 if (thiz)
02125 {
02126 if (thiz->filename) g_string_free(thiz->filename, TRUE);
02127 if (thiz->filename_display) g_string_free(thiz->filename_display, TRUE);
02128 if (thiz->filetype) g_string_free(thiz->filetype, TRUE);
02129 if (thiz->directory_path) g_string_free(thiz->directory_path, TRUE);
02130 g_free(thiz);
02131 }
02132 }
02133
02134
02135 filelist_entry_t* filelist_entry_copy ( const filelist_entry_t *src )
02136 {
02137
02138 g_assert(src);
02139 g_assert(src->filename && src->filename->str);
02140 g_assert(src->filename_display && src->filename_display->str);
02141 g_assert(src->filetype && src->filetype->str);
02142 g_assert(src->directory_path && src->directory_path->str);
02143
02144 filelist_entry_t *thiz = filelist_entry_new();
02145 thiz->filename = g_string_new(src->filename->str);
02146 thiz->directory_path = g_string_new(src->directory_path->str);
02147 thiz->filename_display = g_string_new(src->filename_display->str);
02148 thiz->filetype = g_string_new(src->filetype->str);
02149 thiz->is_directory = src->is_directory;
02150
02151 return thiz;
02152 }
02153
02154
02155 #if MACHINE_IS_DR800S || MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
02156
02157 static gboolean filelist_entry_equal(const filelist_entry_t *left,
02158 const filelist_entry_t *right)
02159 {
02160 if (left == NULL || right == NULL) return FALSE;
02161 if (strcmp(left->filename->str, right->filename->str) != 0) return FALSE;
02162 if (strcmp(left->directory_path->str, right->directory_path->str) != 0) return FALSE;
02163 return TRUE;
02164 }
02165
02166
02167 void filemodel_update_last_read(const filelist_entry_t *fileinfo)
02168 {
02169
02170 if (fileinfo->directory_path->str[0] == 0) return;
02171
02172 if (!filelist_entry_equal(g_last_read, fileinfo)) {
02173 clear_last_read();
02174 g_last_read = filelist_entry_copy(fileinfo);
02175
02176 time_t now = time(NULL);
02177 int rc = db_query_update_lastread(fileinfo->filename, fileinfo->directory_path, now);
02178 if (rc != ER_OK) ERRORPRINTF("cannot update database");
02179 }
02180 }
02181 #endif
02182
02183
02184 #if (TIMING_ON)
02185 static u_int64_t get_time_now()
02186 {
02187 struct timespec now;
02188 clock_gettime(CLOCK_MONOTONIC, &now);
02189 u_int64_t now64 = now.tv_sec;
02190 now64 *= 1000000;
02191 now64 += (now.tv_nsec/1000);
02192 return now64;
02193 }
02194
02195 static u_int64_t t1 = 0;
02196 static u_int64_t t2 = 0;
02197
02198 void start_duration_timer()
02199 {
02200 LOGPRINTF("");
02201 if (t1 == 0) t1 = get_time_now();
02202 }
02203
02204
02205 void stop_duration_timer()
02206 {
02207 if (t1 != 0) {
02208 t2 = get_time_now();
02209 float duration = t2 - t1;
02210 printf("ACTION DURATION = %4.1lf ms\n\n", duration / 1000);
02211 t1 = 0;
02212 }
02213 }
02214 #endif
02215