static void cache_manager_standard_clean_start_cb(GenericDialog *gd, gpointer data) { CleanData *cd = data; GList *list; gchar *path; FileData *dir_fd; #if GTK_CHECK_VERSION(2,20,0) if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return; #else if (cd->list || !GTK_WIDGET_SENSITIVE(cd->button_start)) return; #endif gtk_widget_set_sensitive(cd->button_start, FALSE); gtk_widget_set_sensitive(cd->button_stop, TRUE); gtk_widget_set_sensitive(cd->button_close, FALSE); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("running...")); path = g_build_filename(homedir(), THUMB_FOLDER_GLOBAL, THUMB_FOLDER_NORMAL, NULL); dir_fd = file_data_new_simple(path); filelist_read(dir_fd, &list, NULL); cd->list = list; file_data_unref(dir_fd); g_free(path); path = g_build_filename(homedir(), THUMB_FOLDER_GLOBAL, THUMB_FOLDER_LARGE, NULL); dir_fd = file_data_new_simple(path); filelist_read(dir_fd, &list, NULL); cd->list = g_list_concat(cd->list, list); file_data_unref(dir_fd); g_free(path); path = g_build_filename(homedir(), THUMB_FOLDER_GLOBAL, THUMB_FOLDER_FAIL, NULL); dir_fd = file_data_new_simple(path); filelist_read(dir_fd, &list, NULL); cd->list = g_list_concat(cd->list, list); file_data_unref(dir_fd); g_free(path); cd->count_total = g_list_length(cd->list); cd->count_done = 0; /* start iterating */ if (cd->clear) { cd->idle_id = g_idle_add(cache_manager_standard_clean_clear_cb, cd); } else { cache_manager_standard_clean_valid_cb(NULL, TRUE, cd); } }
static void vdtree_add_by_data(ViewDir *vd, FileData *fd, GtkTreeIter *parent) { GtkTreeStore *store; GtkTreeIter child; NodeData *nd; GdkPixbuf *pixbuf; NodeData *end; GtkTreeIter empty; if (!fd) return; if (access_file(fd->path, R_OK | X_OK)) { pixbuf = vd->pf->close; } else { pixbuf = vd->pf->deny; } nd = g_new0(NodeData, 1); nd->fd = fd; nd->version = fd->version; nd->expanded = FALSE; nd->last_update = time(NULL); store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view))); gtk_tree_store_append(store, &child, parent); gtk_tree_store_set(store, &child, DIR_COLUMN_POINTER, nd, DIR_COLUMN_ICON, pixbuf, DIR_COLUMN_NAME, nd->fd->name, DIR_COLUMN_COLOR, FALSE, -1); /* all nodes are created with an "empty" node, so that the expander is shown * this is removed when the child is populated */ end = g_new0(NodeData, 1); end->fd = file_data_new_simple(""); end->expanded = TRUE; gtk_tree_store_append(store, &empty, &child); gtk_tree_store_set(store, &empty, DIR_COLUMN_POINTER, end, DIR_COLUMN_NAME, "empty", -1); if (parent) { NodeData *pnd; GtkTreePath *tpath; gtk_tree_model_get(GTK_TREE_MODEL(store), parent, DIR_COLUMN_POINTER, &pnd, -1); tpath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), parent); if (options->tree_descend_subdirs && gtk_tree_view_row_expanded(GTK_TREE_VIEW(vd->view), tpath) && !nd->expanded) { vdtree_populate_path_by_iter(vd, &child, FALSE, vd->dir_fd); } gtk_tree_path_free(tpath); } }
static void collect_manager_refresh(void) { GList *list; GList *work; FileData *dir_fd; dir_fd = file_data_new_simple(get_collections_dir()); filelist_read(dir_fd, &list, NULL); file_data_unref(dir_fd); work = collection_manager_entry_list; while (work && list) { CollectManagerEntry *entry; GList *list_step; entry = work->data; work = work->next; list_step = list; while (list_step && entry) { FileData *fd; fd = list_step->data; list_step = list_step->next; if (strcmp(fd->path, entry->path) == 0) { list = g_list_remove(list, fd); file_data_unref(fd); entry = NULL; } else { collect_manager_entry_free(entry); } } } work = list; while (work) { FileData *fd; fd = work->data; work = work->next; collect_manager_entry_new(fd->path); } filelist_free(list); }
static void vdtree_setup_root(ViewDir *vd) { const gchar *path = G_DIR_SEPARATOR_S; FileData *fd; fd = file_data_new_simple(path); vdtree_add_by_data(vd, fd, NULL); vdtree_expand_by_data(vd, fd, TRUE); vdtree_populate_path(vd, fd, FALSE, FALSE); }
static void vd_rename_finished_cb(gboolean success, const gchar *new_path, gpointer data) { ViewDir *vd = data; if (success) { FileData *fd = file_data_new_simple(new_path); GtkTreeIter iter; if (vd_find_row(vd, fd, &iter)) { tree_view_row_make_visible(GTK_TREE_VIEW(vd->view), &iter, TRUE); } file_data_unref(fd); } }
static void cache_manager_render_start_cb(GenericDialog *fd, gpointer data) { CleanData *cd = data; gchar *path; #if GTK_CHECK_VERSION(2,20,0) if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return; #else if (cd->list || !GTK_WIDGET_SENSITIVE(cd->button_start)) return; #endif path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(cd->entry)))); parse_out_relatives(path); if (!isdir(path)) { warning_dialog(_("Invalid folder"), _("The specified folder can not be found."), GTK_STOCK_DIALOG_WARNING, cd->gd->dialog); } else { FileData *dir_fd; gtk_widget_set_sensitive(cd->group, FALSE); gtk_widget_set_sensitive(cd->button_start, FALSE); gtk_widget_set_sensitive(cd->button_stop, TRUE); gtk_widget_set_sensitive(cd->button_close, FALSE); spinner_set_interval(cd->spinner, SPINNER_SPEED); dir_fd = file_data_new_simple(path); cache_manager_render_folder(cd, dir_fd); file_data_unref(dir_fd); while (cache_manager_render_file(cd)); } g_free(path); }
gboolean metadata_write_perform(FileData *fd) { gboolean success; ExifData *exif; g_assert(fd->change); if (fd->change->dest && strcmp(extension_from_path(fd->change->dest), GQ_CACHE_EXT_METADATA) == 0) { success = metadata_legacy_write(fd); if (success) metadata_legacy_delete(fd, fd->change->dest); return success; } /* write via exiv2 */ /* we can either use cached metadata which have fd->modified_xmp already applied or read metadata from file and apply fd->modified_xmp metadata are read also if the file was modified meanwhile */ exif = exif_read_fd(fd); if (!exif) return FALSE; success = (fd->change->dest) ? exif_write_sidecar(exif, fd->change->dest) : exif_write(exif); /* write modified metadata */ exif_free_fd(fd, exif); if (fd->change->dest) /* this will create a FileData for the sidecar and link it to the main file (we can't wait until the sidecar is discovered by directory scanning because exif_read_fd is called before that and it would read the main file only and store the metadata in the cache) FIXME: this does not catch new sidecars created by independent external programs */ file_data_unref(file_data_new_simple(fd->change->dest)); if (success) metadata_legacy_delete(fd, fd->change->dest); return success; }
static gboolean collection_load_private(CollectionData *cd, const gchar *path, CollectionLoadFlags flags) { gchar s_buf[GQ_COLLECTION_READ_BUFSIZE]; FILE *f; gchar *pathl; gboolean limit_failures = TRUE; gboolean success = TRUE; gboolean has_official_header = FALSE; gboolean has_geometry_header = FALSE; gboolean has_gqview_header = FALSE; gboolean need_header = TRUE; guint total = 0; guint fail = 0; gboolean changed = FALSE; CollectManagerEntry *entry = NULL; guint flush = !!(flags & COLLECTION_LOAD_FLUSH); guint append = !!(flags & COLLECTION_LOAD_APPEND); guint only_geometry = !!(flags & COLLECTION_LOAD_GEOMETRY); if (!only_geometry) { collection_load_stop(cd); if (flush) collect_manager_flush(); else entry = collect_manager_get_entry(path); if (!append) { collection_list_free(cd->list); cd->list = NULL; } } if (!path && !cd->path) return FALSE; if (!path) path = cd->path; DEBUG_1("collection load: append=%d flush=%d only_geometry=%d path=%s", append, flush, only_geometry, path); /* load it */ pathl = path_from_utf8(path); f = fopen(pathl, "r"); g_free(pathl); if (!f) { log_printf("Failed to open collection file: \"%s\"\n", path); return FALSE; } while (fgets(s_buf, sizeof(s_buf), f)) { gchar *buf; gchar *p = s_buf; /* Skip whitespaces and empty lines */ while (*p && g_ascii_isspace(*p)) p++; if (*p == '\n' || *p == '\r') continue; /* Parse comments */ if (*p == '#') { if (!need_header) continue; if (g_ascii_strncasecmp(p, GQ_COLLECTION_MARKER, strlen(GQ_COLLECTION_MARKER)) == 0) { /* Looks like an official collection, allow unchecked input. * All this does is allow adding files that may not exist, * which is needed for the collection manager to work. * Also unofficial files abort after too many invalid entries. */ has_official_header = TRUE; limit_failures = FALSE; } else if (strncmp(p, "#geometry:", 10 ) == 0 && scan_geometry(p + 10, &cd->window_x, &cd->window_y, &cd->window_w, &cd->window_h)) { has_geometry_header = TRUE; cd->window_read = TRUE; if (only_geometry) break; } else if (g_ascii_strncasecmp(p, "#GQview collection", strlen("#GQview collection")) == 0) { /* As 2008/04/15 there is no difference between our collection file format * and GQview 2.1.5 collection file format so ignore failures as well. */ has_gqview_header = TRUE; limit_failures = FALSE; } need_header = (!has_official_header && !has_gqview_header) || !has_geometry_header; continue; } if (only_geometry) continue; /* Read filenames */ while (*p && *p != '"') p++; if (*p) p++; buf = p; while (*p && *p != '"') p++; *p = 0; if (*buf) { gboolean valid; if (!flush) changed |= collect_manager_process_action(entry, &buf); valid = (buf[0] == G_DIR_SEPARATOR && collection_add_check(cd, file_data_new_simple(buf), FALSE, TRUE)); if (!valid) DEBUG_1("collection invalid file: %s", buf); total++; if (!valid) { fail++; if (limit_failures && fail > GQ_COLLECTION_FAIL_MIN && fail * 100 / total > GQ_COLLECTION_FAIL_PERCENT) { log_printf("%d invalid filenames in unofficial collection file, closing: %s\n", fail, path); success = FALSE; break; } } } } DEBUG_1("collection files: total = %d fail = %d official=%d gqview=%d geometry=%d", total, fail, has_official_header, has_gqview_header, has_geometry_header); fclose(f); if (only_geometry) return has_geometry_header; if (!flush) { gchar *buf = NULL; while (collect_manager_process_action(entry, &buf)) { collection_add_check(cd, file_data_new_simple(buf), FALSE, TRUE); changed = TRUE; g_free(buf); buf = NULL; } } cd->list = collection_list_sort(cd->list, cd->sort_method); if (!flush && changed && success) collection_save_private(cd, path); if (!flush) collect_manager_entry_reset(entry); if (!append) cd->changed = FALSE; return success; }
/* This checks relative caches in dir/.thumbnails and * removes them if they have no source counterpart. */ gint cache_maintain_dir(FileData *dir_fd, gint recursive, gint clear) { GList *list = NULL; gchar *cachedir; FileData *cachedir_fd; gboolean still_have_a_file = FALSE; GList *work; cachedir = g_build_filename(dir, GQ_CACHE_LOCAL_THUMB, NULL); cachedir_fd = file_data_new_simple(cachedir); g_free(cachedir); filelist_read(cachedir_fd, &list, NULL); work = list; while (work) { FileData *fd; gchar *source; fd = work->data; work = work->next; source = g_build_filename(dir->path, fd->name, NULL); if (clear || extension_truncate(source, GQ_CACHE_EXT_THUMB) || extension_truncate(source, GQ_CACHE_EXT_SIM)) { if (!clear && isfile(source)) { still_have_a_file = TRUE; } else { if (!unlink_file(fd->path)) { DEBUG_1("Failed to remove cache file %s", fd->path); still_have_a_file = TRUE; } } } else { still_have_a_file = TRUE; } g_free(source); } filelist_free(list); file_data_unref(cachedir_fd); if (recursive) { list = NULL; filelist_read(dir_fd, NULL, &list); work = list; while (work) { FileData *fd = work->data; work = work->next; still_have_a_file |= cache_maintain_dir(fd->path, recursive, clear); } filelist_free(list); } return still_have_a_file; }
/* This checks all files in ~/GQ_RC_DIR/thumbnails and * removes them if thay have no source counterpart. * (this assumes all cache files have an extension of 4 chars including '.') */ gint cache_maintain_home_dir(const gchar *dir, gint recursive, gint clear) { gchar *base; gint base_length; GList *dlist = NULL; FileData *dir_fd; GList *flist = NULL; gboolean still_have_a_file = FALSE; DEBUG_1("maintainance check: %s", dir); base_length = strlen(homedir()) + strlen("/") + strlen(GQ_CACHE_RC_THUMB); base = g_strconcat(homedir(), "/", GQ_CACHE_RC_THUMB, dir, NULL); dir_fd = file_data_new_simple(base); g_free(base); if (filelist_read(dir_fd, &flist, &dlist)) { GList *work; work = dlist; while (work) { FileData *fd = work->data; if (recursive && strlen(fd->path) > base_length && !cache_maintain_home_dir(fd->path + base_length, recursive, clear)) { DEBUG_1("Deleting thumb dir: %s", fd->path); if (!rmdir_utf8(fd->path)) { log_printf("Unable to delete dir: %s\n", fd->path); } } else { still_have_a_file = TRUE; } work = work->next; } work = flist; while (work) { FileData *fd = work->data; gchar *path = g_strdup(fd->path); gchar *dot; dot = extension_find_dot(path); if (dot) *dot = '\0'; if (clear || (strlen(path) > base_length && !isfile(path + base_length)) ) { if (dot) *dot = '.'; if (!unlink_file(path)) log_printf("failed to delete:%s\n", path); } else { still_have_a_file = TRUE; } g_free(path); work = work->next; } } filelist_free(dlist); filelist_free(flist); file_data_unref(dir_fd); return still_have_a_file; }
/* sorry for complexity (cm->done_list), but need it to remove empty dirs */ void cache_maintain_home(gboolean metadata, gboolean clear, GtkWidget *parent) { CMData *cm; GList *dlist; FileData *dir_fd; const gchar *msg; const gchar *cache_folder; GtkWidget *hbox; if (metadata) { cache_folder = get_metadata_cache_dir(); } else { cache_folder = get_thumbnails_cache_dir(); } dir_fd = file_data_new_simple(cache_folder); if (!filelist_read(dir_fd, NULL, &dlist)) { file_data_unref(dir_fd); return; } dlist = g_list_append(dlist, dir_fd); cm = g_new0(CMData, 1); cm->list = dlist; cm->done_list = NULL; cm->clear = clear; cm->metadata = metadata; if (metadata) { msg = _("Removing old metadata..."); } else if (clear) { msg = _("Clearing cached thumbnails..."); } else { msg = _("Removing old thumbnails..."); } cm->gd = generic_dialog_new(_("Maintenance"), "main_maintenance", parent, FALSE, NULL, cm); cm->gd->cancel_cb = cache_maintain_home_close_cb; cm->button_close = generic_dialog_add_button(cm->gd, GTK_STOCK_CLOSE, NULL, cache_maintain_home_close_cb, FALSE); gtk_widget_set_sensitive(cm->button_close, FALSE); cm->button_stop = generic_dialog_add_button(cm->gd, GTK_STOCK_STOP, NULL, cache_maintain_home_stop_cb, FALSE); generic_dialog_add_message(cm->gd, NULL, msg, NULL); gtk_window_set_default_size(GTK_WINDOW(cm->gd->dialog), PURGE_DIALOG_WIDTH, -1); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(cm->gd->vbox), hbox, FALSE, FALSE, 5); gtk_widget_show(hbox); cm->entry = gtk_entry_new(); GTK_WIDGET_UNSET_FLAGS(cm->entry, GTK_CAN_FOCUS); gtk_editable_set_editable(GTK_EDITABLE(cm->entry), FALSE); gtk_box_pack_start(GTK_BOX(hbox), cm->entry, TRUE, TRUE, 0); gtk_widget_show(cm->entry); cm->spinner = spinner_new(NULL, SPINNER_SPEED); gtk_box_pack_start(GTK_BOX(hbox), cm->spinner, FALSE, FALSE, 0); gtk_widget_show(cm->spinner); gtk_widget_show(cm->gd->dialog); cm->idle_id = g_idle_add(cache_maintain_home_cb, cm); }
void pan_calendar_update(PanWindow *pw, PanItem *pi_day) { PanItem *pbox; PanItem *pi; GList *list; GList *work; gint x1, y1, x2, y2, x3, y3; gint x, y, w, h; gint grid; gint column; while ((pi = pan_item_find_by_key(pw, PAN_ITEM_NONE, "day_bubble"))) pan_item_remove(pw, pi); if (!pi_day || pi_day->type != PAN_ITEM_BOX || !pi_day->key || strcmp(pi_day->key, "day") != 0) return; list = pan_layout_intersect(pw, pi_day->x, pi_day->y, pi_day->width, pi_day->height); work = list; while (work) { PanItem *dot; GList *node; dot = work->data; node = work; work = work->next; if (dot->type != PAN_ITEM_BOX || !dot->fd || !dot->key || strcmp(dot->key, "dot") != 0) { list = g_list_delete_link(list, node); } } #if 0 if (!list) return; #endif grid = (gint)(sqrt(g_list_length(list)) + 0.5); x = pi_day->x + pi_day->width + 4; y = pi_day->y; #if 0 if (y + grid * (PAN_THUMB_SIZE + PAN_THUMB_GAP) + PAN_BOX_BORDER * 4 > pw->pr->image_height) { y = pw->pr->image_height - (grid * (PAN_THUMB_SIZE + PAN_THUMB_GAP) + PAN_BOX_BORDER * 4); } #endif pbox = pan_item_box_new(pw, NULL, x, y, PAN_BOX_BORDER, PAN_BOX_BORDER, PAN_CAL_POPUP_BORDER, PAN_CAL_POPUP_COLOR, PAN_CAL_POPUP_ALPHA, PAN_CAL_POPUP_BORDER_COLOR, PAN_CAL_POPUP_ALPHA); pan_item_set_key(pbox, "day_bubble"); if (pi_day->fd) { PanItem *plabel; gchar *buf; buf = pan_date_value_string(pi_day->fd->date, PAN_DATE_LENGTH_WEEK); plabel = pan_item_text_new(pw, x, y, buf, PAN_TEXT_ATTR_BOLD | PAN_TEXT_ATTR_HEADING, PAN_TEXT_BORDER_SIZE, PAN_CAL_POPUP_TEXT_COLOR, 255); pan_item_set_key(plabel, "day_bubble"); g_free(buf); pan_item_size_by_item(pbox, plabel, 0); y += plabel->height; } if (list) { column = 0; x += PAN_BOX_BORDER; y += PAN_BOX_BORDER; work = list; while (work) { PanItem *dot; dot = work->data; work = work->next; if (dot->fd) { PanItem *pimg; pimg = pan_item_thumb_new(pw, file_data_new_simple(dot->fd->path), x, y); pan_item_set_key(pimg, "day_bubble"); pan_item_size_by_item(pbox, pimg, PAN_BOX_BORDER); column++; if (column < grid) { x += PAN_THUMB_SIZE + PAN_THUMB_GAP; } else { column = 0; x = pbox->x + PAN_BOX_BORDER; y += PAN_THUMB_SIZE + PAN_THUMB_GAP; } } } } x1 = pi_day->x + pi_day->width - 8; y1 = pi_day->y + 8; x2 = pbox->x + 1; y2 = pbox->y + MIN(42, pbox->height); x3 = pbox->x + 1; y3 = MAX(pbox->y, y2 - 30); util_clip_triangle(x1, y1, x2, y2, x3, y3, &x, &y, &w, &h); pi = pan_item_tri_new(pw, NULL, x, y, w, h, x1, y1, x2, y2, x3, y3, PAN_CAL_POPUP_COLOR, PAN_CAL_POPUP_ALPHA); pan_item_tri_border(pi, PAN_BORDER_1 | PAN_BORDER_3, PAN_CAL_POPUP_BORDER_COLOR, PAN_CAL_POPUP_ALPHA); pan_item_set_key(pi, "day_bubble"); pan_item_added(pw, pi); pan_item_box_shadow(pbox, PAN_SHADOW_OFFSET * 2, PAN_SHADOW_FADE * 2); pan_item_added(pw, pbox); pan_layout_resize(pw); }
static gboolean vdlist_populate(ViewDir *vd, gboolean clear) { GtkListStore *store; GList *work; GtkTreeIter iter; gboolean valid; gchar *filepath; GList *old_list; gboolean ret; FileData *fd; SortType sort_type = SORT_NAME; gboolean sort_ascend = TRUE; old_list = VDLIST(vd)->list; ret = filelist_read(vd->dir_fd, NULL, &VDLIST(vd)->list); VDLIST(vd)->list = filelist_sort(VDLIST(vd)->list, sort_type, sort_ascend); /* add . and .. */ if (strcmp(vd->dir_fd->path, G_DIR_SEPARATOR_S) != 0) { filepath = g_build_filename(vd->dir_fd->path, "..", NULL); fd = file_data_new_simple(filepath); VDLIST(vd)->list = g_list_prepend(VDLIST(vd)->list, fd); g_free(filepath); } if (options->file_filter.show_dot_directory) { filepath = g_build_filename(vd->dir_fd->path, ".", NULL); fd = file_data_new_simple(filepath); VDLIST(vd)->list = g_list_prepend(VDLIST(vd)->list, fd); g_free(filepath); } store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view))); if (clear) gtk_list_store_clear(store); valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, NULL); work = VDLIST(vd)->list; while (work) { gint match; GdkPixbuf *pixbuf; const gchar *date = ""; gboolean done = FALSE; fd = work->data; if (access_file(fd->path, R_OK | X_OK) && fd->name) { if (fd->name[0] == '.' && fd->name[1] == '\0') { pixbuf = vd->pf->open; } else if (fd->name[0] == '.' && fd->name[1] == '.' && fd->name[2] == '\0') { pixbuf = vd->pf->parent; } else { pixbuf = vd->pf->close; if (vd->layout && vd->layout->options.show_directory_date) date = text_from_time(fd->date); } } else { pixbuf = vd->pf->deny; } while (!done) { FileData *old_fd = NULL; if (valid) { gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DIR_COLUMN_POINTER, &old_fd, -1); if (fd == old_fd) { match = 0; } else { match = filelist_sort_compare_filedata_full(fd, old_fd, sort_type, sort_ascend); if (match == 0) g_warning("multiple fd for the same path"); } } else { match = -1; } if (match < 0) { GtkTreeIter new; if (valid) { gtk_list_store_insert_before(store, &new, &iter); } else { gtk_list_store_append(store, &new); } gtk_list_store_set(store, &new, DIR_COLUMN_POINTER, fd, DIR_COLUMN_ICON, pixbuf, DIR_COLUMN_NAME, fd->name, DIR_COLUMN_DATE, date, -1); done = TRUE; } else if (match > 0)
gboolean vdtree_populate_path_by_iter(ViewDir *vd, GtkTreeIter *iter, gboolean force, FileData *target_fd) { GtkTreeModel *store; GList *list; GList *work; GList *old; time_t current_time; GtkTreeIter child; NodeData *nd; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); if (!nd) return FALSE; current_time = time(NULL); if (nd->expanded) { if (!isdir(nd->fd->path)) { if (vd->click_fd == nd->fd) vd->click_fd = NULL; if (vd->drop_fd == nd->fd) vd->drop_fd = NULL; gtk_tree_store_remove(GTK_TREE_STORE(store), iter); vdtree_node_free(nd); return FALSE; } if (!force && current_time - nd->last_update < 2) { DEBUG_1("Too frequent update of %s", nd->fd->path); return TRUE; } if (nd->fd->version == nd->version) return TRUE; } vdtree_busy_push(vd); filelist_read(nd->fd, NULL, &list); /* when hidden files are not enabled, and the user enters a hidden path, * allow the tree to display that path by specifically inserting the hidden entries */ if (!options->file_filter.show_hidden_files && target_fd && strncmp(nd->fd->path, target_fd->path, strlen(nd->fd->path)) == 0) { gint n; n = strlen(nd->fd->path); if (target_fd->path[n] == G_DIR_SEPARATOR && target_fd->path[n+1] == '.') { gchar *name8; struct stat sbuf; n++; while (target_fd->path[n] != '\0' && target_fd->path[n] != G_DIR_SEPARATOR) n++; name8 = g_strndup(target_fd->path, n); if (stat_utf8(name8, &sbuf)) { list = g_list_prepend(list, file_data_new_simple(name8)); } g_free(name8); } } old = NULL; if (gtk_tree_model_iter_children(store, &child, iter)) { do { NodeData *cnd; gtk_tree_model_get(store, &child, DIR_COLUMN_POINTER, &cnd, -1); old = g_list_prepend(old, cnd); } while (gtk_tree_model_iter_next(store, &child)); } work = list; while (work) { FileData *fd; fd = work->data; work = work->next; if (strcmp(fd->name, ".") == 0 || strcmp(fd->name, "..") == 0) { file_data_unref(fd); } else { NodeData *cnd; cnd = vdtree_find_iter_by_fd(vd, iter, fd, &child); if (cnd) { if (cnd->expanded && cnd->version != fd->version) { vdtree_populate_path_by_iter(vd, &child, FALSE, target_fd); } gtk_tree_store_set(GTK_TREE_STORE(store), &child, DIR_COLUMN_NAME, fd->name, -1); cnd->version = fd->version; old = g_list_remove(old, cnd); file_data_unref(fd); } else { vdtree_add_by_data(vd, fd, iter); } } } work = old; while (work) { NodeData *cnd = work->data; work = work->next; if (vd->click_fd == cnd->fd) vd->click_fd = NULL; if (vd->drop_fd == cnd->fd) vd->drop_fd = NULL; if (vdtree_find_iter_by_data(vd, iter, cnd, &child)) { gtk_tree_store_remove(GTK_TREE_STORE(store), &child); vdtree_node_free(cnd); } } g_list_free(old); g_list_free(list); vdtree_busy_pop(vd); nd->expanded = TRUE; nd->last_update = current_time; return TRUE; }
void pan_timeline_compute(PanWindow *pw, const gchar *path, gint *width, gint *height) { GList *list; GList *work; gint x, y; time_t tc; gint total; gint count; PanItem *pi_month = NULL; PanItem *pi_day = NULL; gint month_start; gint day_start; gint x_width; gint y_height; list = pan_list_tree(path, SORT_NONE, TRUE, pw->ignore_symlinks); if (pw->cache_list && pw->exif_date_enable) { pw->cache_list = filelist_sort(pw->cache_list, SORT_NAME, TRUE); list = filelist_sort(list, SORT_NAME, TRUE); pan_cache_sync_date(pw, list); } pw->cache_list = filelist_sort(pw->cache_list, SORT_TIME, TRUE); list = filelist_sort(list, SORT_TIME, TRUE); *width = PAN_BOX_BORDER * 2; *height = PAN_BOX_BORDER * 2; x = 0; y = 0; month_start = y; day_start = month_start; x_width = 0; y_height = 0; tc = 0; total = 0; count = 0; work = list; while (work) { FileData *fd; PanItem *pi; fd = work->data; work = work->next; if (!pan_date_compare(fd->date, tc, PAN_DATE_LENGTH_DAY)) { GList *needle; gchar *buf; if (!pan_date_compare(fd->date, tc, PAN_DATE_LENGTH_MONTH)) { pi_day = NULL; if (pi_month) { x = pi_month->x + pi_month->width + PAN_BOX_BORDER; } else { x = PAN_BOX_BORDER; } y = PAN_BOX_BORDER; buf = pan_date_value_string(fd->date, PAN_DATE_LENGTH_MONTH); pi = pan_item_text_new(pw, x, y, buf, PAN_TEXT_ATTR_BOLD | PAN_TEXT_ATTR_HEADING, PAN_TEXT_BORDER_SIZE, PAN_TEXT_COLOR, 255); g_free(buf); y += pi->height; pi_month = pan_item_box_new(pw, file_data_new_simple(fd->path), x, y, 0, 0, PAN_BOX_OUTLINE_THICKNESS, PAN_BOX_COLOR, PAN_BOX_ALPHA, PAN_BOX_OUTLINE_COLOR, PAN_BOX_OUTLINE_ALPHA); x += PAN_BOX_BORDER; y += PAN_BOX_BORDER; month_start = y; } if (pi_day) x = pi_day->x + pi_day->width + PAN_BOX_BORDER; tc = fd->date; total = 1; count = 0; needle = work; while (needle) { FileData *nfd; nfd = needle->data; if (pan_date_compare(nfd->date, tc, PAN_DATE_LENGTH_DAY)) { needle = needle->next; total++; } else { needle = NULL; } } buf = pan_date_value_string(fd->date, PAN_DATE_LENGTH_WEEK); pi = pan_item_text_new(pw, x, y, buf, PAN_TEXT_ATTR_NONE, PAN_TEXT_BORDER_SIZE, PAN_TEXT_COLOR, 255); g_free(buf); y += pi->height; pi_day = pan_item_box_new(pw, file_data_new_simple(fd->path), x, y, 0, 0, PAN_BOX_OUTLINE_THICKNESS, PAN_BOX_COLOR, PAN_BOX_ALPHA, PAN_BOX_OUTLINE_COLOR, PAN_BOX_OUTLINE_ALPHA); x += PAN_BOX_BORDER; y += PAN_BOX_BORDER; day_start = y; } if (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) { pi = pan_item_image_new(pw, fd, x, y, 10, 10); if (pi->width > x_width) x_width = pi->width; y_height = pi->height; } else { pi = pan_item_thumb_new(pw, fd, x, y); x_width = PAN_THUMB_SIZE; y_height = PAN_THUMB_SIZE; } pan_item_size_by_item(pi_day, pi, PAN_BOX_BORDER); pan_item_size_by_item(pi_month, pi_day, PAN_BOX_BORDER); total--; count++; if (total > 0 && count < PAN_GROUP_MAX) { y += y_height + PAN_THUMB_GAP; } else { x += x_width + PAN_THUMB_GAP; x_width = 0; count = 0; if (total > 0) y = day_start; else y = month_start; } pan_item_size_coordinates(pi_month, PAN_BOX_BORDER, width, height); } g_list_free(list); }
void pan_calendar_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *height) { GList *list; GList *work; gint x, y; time_t tc; gint count; gint day_max; gint day_width; gint day_height; gint grid; gint year = 0; gint month = 0; gint end_year = 0; gint end_month = 0; list = pan_list_tree(dir_fd, SORT_NONE, TRUE, pw->ignore_symlinks); if (pw->cache_list && pw->exif_date_enable) { pw->cache_list = pan_cache_sort(pw->cache_list, SORT_NAME, TRUE); list = filelist_sort(list, SORT_NAME, TRUE); pan_cache_sync_date(pw, list); } pw->cache_list = pan_cache_sort(pw->cache_list, SORT_TIME, TRUE); list = filelist_sort(list, SORT_TIME, TRUE); day_max = 0; count = 0; tc = 0; work = list; while (work) { FileData *fd; fd = work->data; work = work->next; if (!pan_date_compare(fd->date, tc, PAN_DATE_LENGTH_DAY)) { count = 0; tc = fd->date; } else { count++; if (day_max < count) day_max = count; } } DEBUG_1("biggest day contains %d images", day_max); grid = (gint)(sqrt((gdouble)day_max) + 0.5) * (PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2 + PAN_THUMB_GAP); day_width = MAX(PAN_CAL_DAY_WIDTH, grid); day_height = MAX(PAN_CAL_DAY_HEIGHT, grid); if (list) { FileData *fd = list->data; year = pan_date_value(fd->date, PAN_DATE_LENGTH_YEAR); month = pan_date_value(fd->date, PAN_DATE_LENGTH_MONTH); } work = g_list_last(list); if (work) { FileData *fd = work->data; end_year = pan_date_value(fd->date, PAN_DATE_LENGTH_YEAR); end_month = pan_date_value(fd->date, PAN_DATE_LENGTH_MONTH); } *width = PAN_BOX_BORDER * 2; *height = PAN_BOX_BORDER * 2; x = PAN_BOX_BORDER; y = PAN_BOX_BORDER; work = list; while (work && (year < end_year || (year == end_year && month <= end_month))) { PanItem *pi_month; PanItem *pi_text; gint day; gint days; gint col; gint row; time_t dt; gchar *buf; /* figure last second of this month */ dt = pan_date_to_time((month == 12) ? year + 1 : year, (month == 12) ? 1 : month + 1, 1); dt -= 60 * 60 * 24; /* anything to show this month? */ if (!pan_date_compare(((FileData *)(work->data))->date, dt, PAN_DATE_LENGTH_MONTH)) { month ++; if (month > 12) { year++; month = 1; } continue; } days = pan_date_value(dt, PAN_DATE_LENGTH_DAY); dt = pan_date_to_time(year, month, 1); col = pan_date_value(dt, PAN_DATE_LENGTH_WEEK); row = 1; x = PAN_BOX_BORDER; pi_month = pan_item_box_new(pw, NULL, x, y, PAN_CAL_DAY_WIDTH * 7, PAN_CAL_DAY_HEIGHT / 4, PAN_CAL_MONTH_BORDER, PAN_CAL_MONTH_COLOR, PAN_CAL_MONTH_ALPHA, PAN_CAL_MONTH_BORDER_COLOR, PAN_CAL_MONTH_ALPHA); buf = pan_date_value_string(dt, PAN_DATE_LENGTH_MONTH); pi_text = pan_item_text_new(pw, x, y, buf, PAN_TEXT_ATTR_BOLD | PAN_TEXT_ATTR_HEADING, PAN_TEXT_BORDER_SIZE, PAN_CAL_MONTH_TEXT_COLOR, 255); g_free(buf); pi_text->x = pi_month->x + (pi_month->width - pi_text->width) / 2; pi_month->height = pi_text->y + pi_text->height - pi_month->y; x = PAN_BOX_BORDER + col * PAN_CAL_DAY_WIDTH; y = pi_month->y + pi_month->height + PAN_BOX_BORDER; for (day = 1; day <= days; day++) { FileData *fd; PanItem *pi_day; gint dx, dy; gint n = 0; gchar fake_path[20]; dt = pan_date_to_time(year, month, day); /* * Create a FileData entry that represents the given day. * It does not correspond to any real file */ g_snprintf(fake_path, sizeof(fake_path), "//%04d-%02d-%02d", year, month, day); fd = file_data_new_simple(fake_path); fd->date = dt; pi_day = pan_item_box_new(pw, fd, x, y, PAN_CAL_DAY_WIDTH, PAN_CAL_DAY_HEIGHT, PAN_CAL_DAY_BORDER, PAN_CAL_DAY_COLOR, PAN_CAL_DAY_ALPHA, PAN_CAL_DAY_BORDER_COLOR, PAN_CAL_DAY_ALPHA); pan_item_set_key(pi_day, "day"); dx = x + PAN_CAL_DOT_GAP * 2; dy = y + PAN_CAL_DOT_GAP * 2; fd = (work) ? work->data : NULL; while (fd && pan_date_compare(fd->date, dt, PAN_DATE_LENGTH_DAY)) { PanItem *pi; pi = pan_item_box_new(pw, fd, dx, dy, PAN_CAL_DOT_SIZE, PAN_CAL_DOT_SIZE, 0, PAN_CAL_DOT_COLOR, PAN_CAL_DOT_ALPHA, 0, 0, 0, 0); pan_item_set_key(pi, "dot"); dx += PAN_CAL_DOT_SIZE + PAN_CAL_DOT_GAP; if (dx + PAN_CAL_DOT_SIZE > pi_day->x + pi_day->width - PAN_CAL_DOT_GAP * 2) { dx = x + PAN_CAL_DOT_GAP * 2; dy += PAN_CAL_DOT_SIZE + PAN_CAL_DOT_GAP; } if (dy + PAN_CAL_DOT_SIZE > pi_day->y + pi_day->height - PAN_CAL_DOT_GAP * 2) { /* must keep all dots within respective day even if it gets ugly */ dy = y + PAN_CAL_DOT_GAP * 2; } n++; work = work->next; fd = (work) ? work->data : NULL; } if (n > 0) { PanItem *pi; pi_day->color_r = MAX(pi_day->color_r - 61 - n * 3, 80); pi_day->color_g = pi_day->color_r; buf = g_strdup_printf("( %d )", n); pi = pan_item_text_new(pw, x, y, buf, PAN_TEXT_ATTR_NONE, PAN_TEXT_BORDER_SIZE, PAN_CAL_DAY_TEXT_COLOR, 255); g_free(buf); pi->x = pi_day->x + (pi_day->width - pi->width) / 2; pi->y = pi_day->y + (pi_day->height - pi->height) / 2; } buf = g_strdup_printf("%d", day); pan_item_text_new(pw, x + 4, y + 4, buf, PAN_TEXT_ATTR_BOLD | PAN_TEXT_ATTR_HEADING, PAN_TEXT_BORDER_SIZE, PAN_CAL_DAY_TEXT_COLOR, 255); g_free(buf); pan_item_size_coordinates(pi_day, PAN_BOX_BORDER, width, height); col++; if (col > 6) { col = 0; row++; x = PAN_BOX_BORDER; y += PAN_CAL_DAY_HEIGHT; } else { x += PAN_CAL_DAY_WIDTH; } } if (col > 0) y += PAN_CAL_DAY_HEIGHT; y += PAN_BOX_BORDER * 2; month ++; if (month > 12) { year++; month = 1; } } *width += grid; *height = MAX(*height, grid + PAN_BOX_BORDER * 2 * 2); g_list_free(list); }