/* Copyright (C) 2000-2003 Markus Lausser (sgop@users.sf.net) This is free software distributed under the terms of the GNU Public License. See the file COPYING for details. */ #include #include "global.h" #include "file_tree.h" #include "search.h" #include "utils.h" #include "files.h" #include "scheme.h" #include "filetips.h" #include "support.h" //#define TREE_DEBUG 1 static file_tree_t* popup_tree = NULL; void download_file(file_t * file, char* search_string, char* dir); /** initializes a file node */ void file_node_init(file_node_t* node, char* name) { int i1, i2; if (!node) return; if (name) node->name = g_strdup(name); else node->name = NULL; node->parent = NULL; node->child = NULL; node->next = NULL; node->prev = NULL; node->file = NULL; for (i1 = 0; i1 <= MEDIA_SIZE; i1++) { for (i2 = 0; i2 <= 3; i2++) { node->fci[i1][i2] = 0; node->fsi[i1][i2] = 0.; } } node->flags = 0; } /** destroys the node, its not removed from the UI! */ void file_node_destroy(file_tree_t* tree, file_node_t* node) { file_node_t* child; file_node_t* next; if (!node) return; if (tree->node_free) tree->node_free(node); if (node->name) g_free(node->name); if (node->file) file_destroy(node->file); child = node->child; while (child) { next = child->next; file_node_destroy(tree, child); child = next; } node->child = NULL; g_free(node); } /** gets pixmap for node */ static void file_node_get_pixmaps(file_tree_t* tree, file_node_t* node, GdkPixmap** pixmap, GdkBitmap** bitmap) { if (node->fci[tree->show_mime][1] == 0) { *pixmap = global.pix.share_none; *bitmap = global.pix.share_noneb; } else if (tree->show_time == 0) { *pixmap = global.pix.share_none; *bitmap = global.pix.share_noneb; } else if (tree->show_time == 1) { *pixmap = global.pix.share_all; *bitmap = global.pix.share_allb; } else if (node->fci[tree->show_mime][1] < node->fci[tree->show_mime][3]) { *pixmap = global.pix.share_part; *bitmap = global.pix.share_partb; } else { *pixmap = global.pix.share_all; *bitmap = global.pix.share_allb; } } /** Shows the node */ void file_node_show(file_tree_t* tree, file_node_t* child, int check) { GtkCList* clist; int row; GdkPixmap* pixmap; GdkBitmap* bitmap; GtkCTreeNode* tnode; if (check && child->fci[tree->show_mime][tree->show_time] == 0) return; file_node_get_pixmaps(tree, child, &pixmap, &bitmap); if (child->file) { clist = tree->clist; strcpy(tstr[0], child->name); sprintf(tstr[1], "%.2f MB", (double) (child->file->size) / 1024 / 1024); if (child->file->vbr) sprintf(tstr[2], "av. %d", child->file->bitrate); else sprintf(tstr[2], "%d", child->file->bitrate); sprintf(tstr[3], "%d", child->file->frequency); print_time_short(tstr[4], child->file->duration); row = gtk_clist_append(clist, list); gtk_clist_set_row_data(clist, row, child); gtk_clist_set_pixtext(clist, row, 0, child->name, 5, pixmap, bitmap); if (child->fci[tree->show_mime][2] > 0) { style_t* style = style_get(global.scheme, "library_marked"); if (style) { gtk_clist_set_foreground(tree->clist, row, style->fore); gtk_clist_set_background(tree->clist, row, style->back); } } } else { tnode = gtk_ctree_find_by_row_data(tree->ctree, NULL, child); if (tnode) return; if (child->parent) { if ((tnode = gtk_ctree_find_by_row_data(tree->ctree, NULL, child->parent)) == NULL) { g_warning("parent not found"); return; } } else tnode = NULL; strcpy(tstr[0], child->name); tnode = gtk_ctree_insert_node(tree->ctree, tnode, GTK_CTREE_ROW (tnode)->children, list, 5, pixmap, bitmap, pixmap, bitmap, FALSE, TRUE); gtk_ctree_node_set_row_data(tree->ctree, tnode, child); } } file_node_t* file_node_search_file(file_node_t* node, file_t* file) { while (node) { if (node->file && !file_compare(node->file, file)) return node; node = node->next; } return 0; } static time_t file_tree_next_mark(file_tree_t* tree, file_node_t* node) { (void)tree; (void)node; return 3600; } void file_tree_init(file_tree_t* tree, char* name, char* des) { int i1, i2; if (!tree) return; if (name) tree->name = g_strdup(name); else tree->name = NULL; if (des) tree->description = g_strdup(des); else tree->description = NULL; tree->last_refreshed = 0; for (i1 = 0; i1 <= MEDIA_SIZE; i1++) { for (i2 = 0; i2 <= 3; i2++) { tree->fci[i1][i2] = 0; tree->fsi[i1][i2] = 0.; } } tree->main_link = NULL; tree->ctree = NULL; tree->clist = NULL; tree->label = NULL; tree->progress = NULL; tree->button[0] = NULL; tree->button[1] = NULL; tree->blabel[0] = NULL; tree->blabel[1] = NULL; tree->resize_cont = NULL; tree->files = NULL; tree->current_node = NULL; tree->show_mime = MEDIA_SIZE; tree->show_time = 3; tree->mark_timeout = -1; tree->search_timeout = -1; tree->search_token = NULL; tree->search_entry = NULL; tree->node_new = NULL; tree->node_status = NULL; tree->update_user = NULL; tree->node_free = NULL; tree->node_init = NULL; tree->next_mark = file_tree_next_mark; tree->signal[0] = -1; tree->signal[1] = -1; tree->signal[2] = -1; tree->signal[3] = -1; tree->signal[4] = -1; tree->signal[5] = -1; tree->signal[6] = -1; tree->signal[7] = -1; } void file_tree_destroy(file_tree_t* tree) { if (!tree) return; if (tree->name) g_free(tree->name); if (tree->description) g_free(tree->description); if (tree->mark_timeout >= 0) gtk_timeout_remove(tree->mark_timeout); g_free(tree); } void file_tree_node_remove(file_tree_t* tree, file_node_t* node) { GtkCTreeNode* tnode1; int row; if (!node) return; // now remove the node if (node->next) node->next->prev = node->prev; if (node->prev) node->prev->next = node->next; if (node->parent) { if (node->parent->child == node) node->parent->child = node->next; } else { tree->files = node->next; } node->next = node->prev = node->parent = NULL; // and hide the node if (node->file && tree->clist) { row = gtk_clist_find_row_from_data(tree->clist, node); if (row >= 0) gtk_clist_remove(tree->clist, row); } if (!node->file && tree->ctree) { tnode1 = gtk_ctree_find_by_row_data(tree->ctree, NULL, node); if (tnode1) gtk_ctree_remove_node(tree->ctree, tnode1); } } static void file_tree_insert_rec(file_tree_t* tree, GtkCTreeNode* node, file_node_t* bnode, int mediatype, int show_time, int check) { GtkCTreeNode* tnode; GdkPixmap* pixmap; GdkBitmap* bitmap; if (check && bnode->fci[mediatype][show_time] == 0) return; strcpy(tstr[0], bnode->name); file_node_get_pixmaps(tree, bnode, &pixmap, &bitmap); tnode = gtk_ctree_insert_node(tree->ctree, node, NULL, list, 5, pixmap, bitmap, pixmap, bitmap, FALSE, TRUE); gtk_ctree_node_set_row_data(tree->ctree, tnode, bnode); if (bnode->fci[tree->show_mime][2] > 0) { style_t* style = style_get(global.scheme, "library_marked"); if (style) { gtk_ctree_node_set_foreground(tree->ctree, tnode, style->fore); gtk_ctree_node_set_background(tree->ctree, tnode, style->back); } } bnode = bnode->child; while (bnode) { if (!bnode->file) file_tree_insert_rec(tree, tnode, bnode, mediatype, show_time, check); bnode = bnode->next; } } static void file_tree_node_insert(file_tree_t* tree, file_node_t* node, file_node_t* child, int check) { GtkCTreeNode* tnode1; if (!child) return; // insert the node if (!node) { child->next = tree->files; if (child->next) child->next->prev = child; child->prev = NULL; child->parent = NULL; tree->files = child; } else { child->next = node->child; child->prev = NULL; if (child->next) child->next->prev = child; node->child = child; child->parent = node; } if (!tree->ctree) return; if (!tree->current_node) tree->current_node = node; // show node if (!child->file) { if (node) tnode1 = gtk_ctree_find_by_row_data(tree->ctree, NULL, node); else tnode1 = NULL; file_tree_insert_rec(tree, tnode1, child, tree->show_mime, tree->show_time, check); } else { if (tree->current_node && node == tree->current_node) file_node_show(tree, child, check); } } static file_node_t* file_tree_split_folder(file_tree_t* tree, file_node_t* node, int pos) { file_node_t* child; char* name; file_node_t* parent; if ((unsigned)pos >= strlen(node->name)) return node; parent = node->parent; name = g_strdup(node->name); // remove the original node file_tree_node_remove(tree, node); g_free(node->name); node->name = g_strdup(name+pos); // insert the new node name[pos] = 0; child = tree->node_new(name); file_tree_node_insert(tree, parent, child, 1); if (tree->node_init) tree->node_init(child); // insert the original node again. file_tree_node_insert(tree, child, node, 1); g_free(name); return child; } file_node_t* file_node_insert_file(file_tree_t* tree, file_node_t* node, file_t* file, gboolean check_dup) { file_node_t* child; if (check_dup) { child = file_node_search_file(node?node->child:tree->files, file); if (child) { // update the file. child->file->net = file->net; file_destroy(file); return child; } } child = tree->node_new(file->filename); child->file = file; file_tree_node_insert(tree, node, child, 1); if (tree->node_init) tree->node_init(child); return child; } file_node_t* file_tree_insert_file(file_tree_t* tree, file_t * file) { char* pos; file_node_t* node; char save; if (file->longname >= file->filename) { printf("*** warning: tree_insert_file(): should never happen\n"); return NULL; } // now insert the file; pos = strrchr(file->longname, DIR_SEP); #if 0 // code out of date if (pos && pos - file->longname >= 2 && pos[-1] == '/') { // Undo XNap behaviour of putting each file in its own numbered // directory e.g. "42//foo.mp3", "43//bar.mp3" which makes it very hard // to browse. pos -= 2; while (*pos != '/') { if (pos == file->longname) { pos = NULL; break; } --pos; } } #endif // cut the filename (file->filename is linked to file->longname!) save = *(file->filename); *(file->filename) = 0; node = file_tree_insert_folder(tree, NULL, file->longname, 1); // append the filename again. *(file->filename) = save; node = file_node_insert_file(tree, node, file, TRUE); if (tree->update_user) tree->update_user(tree); return node; } static int folder_begin(char* str1, char* str2) { int result = 0; int temp = 0; while (1) { if (*str1 != 0 && *str2 != 0) temp++; if ((*str1 == DIR_SEP || *str1 == 0) && (*str2 == DIR_SEP || *str2 == 0)) result = temp; if (*str1 != *str2) break; if (*str1 == 0 || *str2 == 0) break; str1++; str2++; } return result; } file_node_t* file_tree_insert_folder(file_tree_t* tree, file_node_t* parent, char* folder, int check) { file_node_t* node; int length; if (!parent) { node = tree->files; } else { node = parent->child; } while (node) { length = folder_begin(folder, node->name); if (length > 0) { // match if (node->name[length] != 0) node = file_tree_split_folder(tree, node, length); if (folder[length] == 0) return node; return file_tree_insert_folder(tree, node, folder+length, check); } node = node->next; } node = tree->node_new(folder); file_tree_node_insert(tree, parent, node, check); if (tree->node_init) tree->node_init(node); return node; } static void file_tree_show_status(file_tree_t* tree) { char str[256]; char str2[128]; if (!tree->label) return; sprintf(str, "%d = %s", tree->fci[tree->show_mime][tree->show_time], print_size(str2, tree->fsi[tree->show_mime][tree->show_time])); gtk_label_set_text(GTK_LABEL(tree->label), str); } static int file_tree_mark_files_rec(file_tree_t* tree, file_node_t* node, int timeout) { file_node_t* child; style_t* style; GtkCTreeNode* tnode; int temp; int mark = 0; if (node->file) return timeout; child = node->child; while (child) { if (child->file) { if (child->fci[tree->show_mime][2] > 0) { child->flags |= TREE_MARKED; mark++; } else { child->flags &= ~TREE_MARKED; } temp = tree->next_mark(tree, child); if (temp > 0 && (!timeout || temp < timeout)) timeout = temp; } else { timeout = file_tree_mark_files_rec(tree, child, timeout); } child = child->next; } if (mark && (node->flags & TREE_MARKED)) return timeout; if (!mark && !(node->flags & TREE_MARKED)) return timeout; tnode = gtk_ctree_find_by_row_data(tree->ctree, NULL, node); if (!tnode) return timeout; if (mark) { style = style_get(global.scheme, "library_marked"); if (style) { gtk_ctree_node_set_foreground(tree->ctree, tnode, style->fore); gtk_ctree_node_set_background(tree->ctree, tnode, style->back); } node->flags |= TREE_MARKED; } else { gtk_ctree_node_set_foreground(tree->ctree, tnode, NULL); gtk_ctree_node_set_background(tree->ctree, tnode, NULL); node->flags &= ~TREE_MARKED; } return timeout; } static int file_tree_mark_files(gpointer data) { GtkCList* clist; int row; style_t* style; file_node_t* node; file_tree_t* tree = data; long new_timeout = 0; // when next item has to be removed if (!tree || !tree->files) return 0; file_tree_calc_matrix(tree); style = style_get(global.scheme, "library_marked"); #ifdef TREE_DEBUG printf("[FILETREE] (%s) marking now\n", tree->name); #endif new_timeout = file_tree_mark_files_rec(tree, tree->files, new_timeout); clist = tree->clist; row = 0; while (row < clist->rows) { node = gtk_clist_get_row_data(clist, row); if ((node->flags & TREE_MARKED) && style) { gtk_clist_set_foreground(clist, row, style->fore); gtk_clist_set_background(clist, row, style->back); } else if (!(node->flags & TREE_MARKED)) { gtk_clist_set_foreground(clist, row, NULL); gtk_clist_set_background(clist, row, NULL); } row++; } if (tree->show_time == 2) // re-display file_tree_show(tree, tree->show_mime, 2); if (new_timeout > 0) file_tree_mark(tree, new_timeout); return 0; } static char* TNames(int no) { switch (no) { case 0: return "Show unshared"; case 1: return "Show shared"; case 2: return "Show new"; default: return "Show all"; }; } static char *MNames(int no) { switch (no) { case MEDIA_MP3: return "Mp3 files"; case MEDIA_AUDIO: return "Audio files"; case MEDIA_VIDEO: return "Videos"; case MEDIA_APPLICATION: return "Applications"; case MEDIA_IMAGE: return "Images"; case MEDIA_TEXT: return "Text files"; case MEDIA_FOLDER: return "Folder"; case MEDIA_NONE: return "Other"; default: return "Files"; }; } static void file_tree_setup_buttons(file_tree_t* tree) { if (tree->blabel[0]) { gtk_label_set_text(GTK_LABEL(tree->blabel[0]), TNames(tree->show_time)); } if (tree->blabel[1]) { gtk_label_set_text(GTK_LABEL(tree->blabel[1]), MNames(tree->show_mime)); } if (tree->resize_cont) gtk_widget_queue_resize(tree->resize_cont); } void file_tree_show(file_tree_t* tree, int mediatype, int show_time) { file_node_t* node; if (!tree || !tree->ctree || !tree->clist) return; tree->show_mime = mediatype; tree->show_time = show_time; file_tree_setup_buttons(tree); gtk_clist_clear(GTK_CLIST(tree->ctree)); gtk_clist_clear(tree->clist); tree->current_node = NULL; gtk_clist_freeze(GTK_CLIST(tree->ctree)); node = tree->files; while (node) { file_tree_insert_rec(tree, NULL, node, tree->show_mime, tree->show_time, 1); node = node->next; } gtk_clist_thaw(GTK_CLIST(tree->ctree)); file_tree_show_status(tree); } static void file_tree_calc_matrix_rec(file_tree_t* tree, file_node_t* node) { int i1, i2; file_node_t* child; for (i1 = 0; i1 <= MEDIA_SIZE; i1++) { for (i2 = 0; i2 <= 3; i2++) { node->fci[i1][i2] = 0; node->fsi[i1][i2] = 0.; } } if (node->file) { i1 = tree->node_status(tree, node); if (i1 & (1<<2)) { // its a new shared file node->fci[node->file->media_type][2]++; node->fsi[node->file->media_type][2] += node->file->size; node->fci[MEDIA_SIZE][2]++; node->fsi[MEDIA_SIZE][2] += node->file->size; } if (i1 & (1<<1)) { // its an shared file node->fci[node->file->media_type][1]++; node->fsi[node->file->media_type][1] += node->file->size; node->fci[MEDIA_SIZE][1]++; node->fsi[MEDIA_SIZE][1] += node->file->size; } if (i1 & (1<<0)) { // its unshared node->fci[node->file->media_type][0]++; node->fsi[node->file->media_type][0] += node->file->size; node->fci[MEDIA_SIZE][0]++; node->fsi[MEDIA_SIZE][0] += node->file->size; } node->fci[node->file->media_type][3]++; node->fsi[node->file->media_type][3] += node->file->size; node->fci[MEDIA_SIZE][3]++; node->fsi[MEDIA_SIZE][3] += node->file->size; } else { child = node->child; while (child) { // tree->calc_matrix_rec() should also do the trick file_tree_calc_matrix_rec(tree, child); for (i1 = 0; i1 <= MEDIA_SIZE; i1++) { for (i2 = 0; i2 <= 3; i2++) { node->fci[i1][i2] += child->fci[i1][i2]; node->fsi[i1][i2] += child->fsi[i1][i2]; } } child = child->next; } } } void file_tree_calc_matrix(file_tree_t* tree) { int i1, i2; file_node_t* node; for (i1 = 0; i1 <= MEDIA_SIZE; i1++) { for (i2 = 0; i2 <= 3; i2++) { tree->fci[i1][i2] = 0; tree->fsi[i1][i2] = 0.; } } node = tree->files; while (node) { file_tree_calc_matrix_rec(tree, node); for (i1 = 0; i1 <= MEDIA_SIZE; i1++) { for (i2 = 0; i2 <= 3; i2++) { tree->fci[i1][i2] += node->fci[i1][i2]; tree->fsi[i1][i2] += node->fsi[i1][i2]; } } node = node->next; } file_tree_show_status(tree); } void file_tree_mark(file_tree_t* tree, int when) { if (tree->mark_timeout >= 0) { #ifdef TREE_DEBUG printf("[FILETREE] (%s) old timer canceled\n", tree->name); #endif gtk_timeout_remove(tree->mark_timeout); } if (when > 3600 || when < 0) when = 3600; #ifdef TREE_DEBUG printf("[FILETREE] (%s) next update is in %d seconds\n", tree->name, when); #endif if (when > 0) { tree->mark_timeout = gtk_timeout_add(when*1000, file_tree_mark_files, tree); } else { file_tree_mark_files(tree); } } file_node_t* file_node_next(file_node_t* node) { file_node_t* result = NULL; int up = 0; // traverse tree result = node; while (1) { if (!up && result->child) { result = result->child; break; } else if (result->next) { result = result->next; break; } else { result = result->parent; up = 1; } if (!result) break; } return result; } void file_tree_clear_files(file_tree_t *tree) { int i1, i2; file_node_t* node; file_node_t* next; if (!tree) return; // updating user stats for (i1 = 0; i1 <= MEDIA_SIZE; i1++) { for (i2 = 0; i2 <= 3; i2++) { if (i1 != MEDIA_SIZE && i2 != 3) { tree->fci[i1][i2] = 0; tree->fsi[i1][i2] = 0.; } } } node = tree->files; while (node) { next = node->next; file_node_destroy(tree, node); node = next; } tree->files = NULL; if (tree->ctree) gtk_clist_clear(GTK_CLIST(tree->ctree)); if (tree->clist) gtk_clist_clear(tree->clist); if (tree->update_user) tree->update_user(tree); } static void file_tree_show_childs(file_tree_t* tree, file_node_t* node) { GtkCTree* ctree; GtkCList* clist; file_node_t* node2; file_node_t* child; if (!tree) return; ctree = tree->ctree; clist = tree->clist; node2 = tree->current_node; if (node == node2) return; tree->current_node = node; gtk_clist_clear(clist); gtk_clist_freeze(clist); child = node->child; while (child) { if (child->file) file_node_show(tree, child, 1); child = child->next; } gtk_clist_thaw(clist); } static file_node_t* search_cb(file_node_t* node, void* data) { file_tree_t* tree = data; if (!tree || !node->file || !tree->search_token) return NULL; if (tree->search_token[0] == 0) { file_node_show(tree, node, 1); } else if (tree->search_token[1] == 0) { if (strchr(node->file->longname, tree->search_token[0])) file_node_show(tree, node, 1); } else { if (strcasestr(node->file->longname, tree->search_token)) file_node_show(tree, node, 1); } return NULL; } static int file_tree_search_files(gpointer data) { file_tree_t* tree = data; gtk_clist_clear(tree->clist); tree->current_node = NULL; gtk_timeout_remove(tree->search_timeout); tree->search_timeout = -1; if (!tree->files) return 0; if (!tree->search_token) return 0; gtk_clist_freeze(tree->clist); file_node_action(tree, NULL, search_cb, tree); gtk_clist_thaw(tree->clist); return TRUE; } int on_file_tree_search_changed(GtkWidget * widget, void* user_data) { file_tree_t* tree = user_data; char* text; if (!tree || !tree->ctree || !tree->clist) return 0; text = gtk_entry_get_text(GTK_ENTRY(widget)); if (tree->search_token) g_free(tree->search_token); tree->search_token = g_strdup(text); if (tree->search_timeout >= 0) gtk_timeout_remove(tree->search_timeout); tree->search_timeout = gtk_timeout_add(500/(strlen(text)+1), file_tree_search_files, tree); return 0; } void file_tree_search(file_tree_t *tree, search_t *search, int* cnt) { file_node_t* node; node = tree->files; while (node) { if (node->file) { if (search_pattern_fits_file(search->pattern, node->file, 1)) { search_insert_file(search, node->file); (*cnt)++; } if (search->pattern->max_results && (*cnt) >= search->pattern->max_results) break; } node = file_node_next(node); } } void on_file_tree_select_row(GtkCTree *ctree, GList *node, gint column ATTR_UNUSED, gpointer user_data) { file_node_t *file_node; file_tree_t* tree = user_data; file_node = gtk_ctree_node_get_row_data(ctree, GTK_CTREE_NODE(node)); if (!file_node) return; file_tree_show_childs(tree, file_node); } static void file_node_select(file_tree_t* tree, file_node_t* node) { GtkCTreeNode* cnode; GtkCTreeNode* parent; if (!tree || !tree->ctree || !node || node->file) return; cnode = gtk_ctree_find_by_row_data(tree->ctree, NULL, node); if (!cnode) return; // gtk_ctree_unselect_recursive(tree->ctree, NULL); gtk_ctree_select(tree->ctree, cnode); parent = GTK_CTREE_ROW(cnode)->parent; while (parent) { gtk_ctree_expand(tree->ctree, parent); parent = GTK_CTREE_ROW(parent)->parent; } if (gtk_ctree_node_is_visible(tree->ctree, cnode) != GTK_VISIBILITY_FULL) { gtk_ctree_node_moveto(tree->ctree, cnode, 0, 0.5, 0); } } void on_file_select_row(GtkCList *clist, gint row, gint column ATTR_UNUSED, GdkEvent *event ATTR_UNUSED, gpointer user_data) { file_node_t *file_node; file_tree_t* tree = user_data; // dont move to parent if we dont have a quick search result if (tree->current_node) return; file_node = gtk_clist_get_row_data(clist, row); if (!file_node || !file_node->parent) return; // disconnect the tree select callback to prevent that it // shows the child in the clist (thats our quick search) if (tree->signal[0] >= 0) gtk_signal_disconnect(GTK_OBJECT(tree->ctree), tree->signal[0]); file_node_select(tree, file_node->parent); tree->signal[0] = gtk_signal_connect (GTK_OBJECT (tree->ctree), "tree_select_row", GTK_SIGNAL_FUNC (on_file_tree_select_row), tree); } void download_file_node(file_tree_t* tree, file_node_t* node, char* dir, int withdir) { char temp[2048]; file_node_t* child; if (node->fci[tree->show_mime][tree->show_time] == 0) return; if (node->file) { download_file(node->file, NULL, withdir?dir:NULL); } else { child = node->child; sprintf(temp, "%s%s", dir?dir:"", node->name); while (child) { download_file_node(tree, child, temp, withdir); child = child->next; } } } file_node_t* file_node_action(file_tree_t* tree, file_node_t* node, file_node_function_t action, void* data) { file_node_t* temp; file_node_t* temp2; file_node_t* result; if (!tree) return NULL; if (node) result = action(node, data); else result = NULL; if (result) return result; if (node) temp = node->child; else temp = tree->files; while (temp) { temp2 = temp->next; result = file_node_action(tree, temp, action, data); if (result) return result; temp = temp2; } return NULL; } char* file_node_get_folder(file_node_t* node, int* size) { char* result; if (!node) return NULL; // add space that we need. *size += strlen(node->name); if (!node->parent) { // no more parent, we allocate string here // one byte for the \0 result = g_malloc(sizeof(char)*(*size+1)); result[*size] = 0; // thats the return point, now size is index *size = 0; } else { result = file_node_get_folder(node->parent, size); } strcpy(result+(*size), node->name); *size += strlen(node->name); return result; } static file_node_t* file_tree_search_filename_rec(file_node_t* node, char* filename, int offset) { int len; while (node) { len = strlen(node->name); if (!strncmp(node->name, filename+offset, len)) { offset += len; if (filename[offset] == 0) { // filename end if (!node->child) { if (strcmp(node->file->longname, filename)) { printf("*** should not happen\n"); } return node; } else return NULL; } else if (!node->child) { // not end, but no child return NULL; } else { // continue return file_tree_search_filename_rec(node->child, filename, offset); } } node = node->next; } return NULL; } file_node_t* file_tree_search_filename(file_tree_t* tree, char* filename) { if (!tree->files) return NULL; return file_tree_search_filename_rec(tree->files, filename, 0); } static file_node_t* search_file_win_cb(file_node_t* node, void* winname) { if (!node || !node->file) return NULL; if (!strcmp(node->file->winname, (char*)winname)) return node; else return NULL; } file_node_t* file_tree_search_winname(file_tree_t* tree, file_node_t* node, char* fname) { return file_node_action(tree, node, search_file_win_cb, (void*)fname); } /*// BEGIN chelaz@chelaz.de, modified by sgop void file_tree_save_node_plain(FILE* fd, file_node_t* node, int indent) { file_t* file; char str[1024]; while (node) { file = node->file; if (file) { fprintf(fd, "%*s", indent, ""); fprintf(fd, "%s [%5.2f MB]%s\n", file->filename, print_bytes(str, file->size), (node->flags & LIB_VIRTUAL)!=0 ? " [offline]":""); } else if (node->child) { fprintf(fd, "%*s", indent, ""); fprintf(fd, "%s%s\n", node->name, (node->flags & LIB_VIRTUAL)!=0 ? " [offline]":""); lib_save_node_plain_text(fd, node->child, indent+2); fprintf(fd, "%*s\n", indent, ""); } node = node->next; } } void file_tree_save_plain(file_tree_t* tree, char* filename) { FILE *fd; file_tree_t* tree = FILE_TREE(lib); if (!tree) return; if ((fd = fopen(filename_plain_text, "w")) == NULL) { g_warning("Could not save plain file tree %s", filename); return; } fprintf(fd, "BEGIN of list\n" "-----------------------------------------\n"); lib_save_node_plain_text(fd_plain_text, tree->files, 0); fclose(fd_plain_text); } // END chelaz@chelaz.de */ static GList* file_tree_search_filesize_rec(file_node_t* node, file_t* file, GList* ilist) { file_node_t* child; if (!node) return ilist; if (node->file) { /*** [fvg] adapt to allow some marge (interval, max delta =...) */ if (file->size == node->file->size) ilist = g_list_prepend(ilist, node->file); } child = node->child; while (child) { ilist = file_tree_search_filesize_rec(child, file, ilist); child = child->next; } return ilist; } GList* file_tree_search_filesize(file_tree_t* tree, file_t* file) { if (!tree) return NULL; return file_tree_search_filesize_rec(tree->files, file, NULL); } void file_node_update(file_tree_t* tree, file_node_t* node, int p, int c) { int row; GdkPixmap* pixmap; GdkBitmap* bitmap; GtkCTreeNode* tnode; file_node_t* child; if (!tree || !node) return; if (!node->file) { tnode = gtk_ctree_find_by_row_data(tree->ctree, NULL, node); if (tnode) { file_node_get_pixmaps(tree, node, &pixmap, &bitmap); gtk_ctree_node_set_pixtext(tree->ctree, tnode, 0, node->name, 5, pixmap, bitmap); } } else { row = gtk_clist_find_row_from_data(tree->clist, node); if (row >= 0) { file_node_get_pixmaps(tree, node, &pixmap, &bitmap); gtk_clist_set_pixtext(tree->clist, row, 0, node->name, 5, pixmap, bitmap); } } if (p && node->parent) file_node_update(tree, node->parent, 1, 0); if (c && node->child) { child = node->child; while (child) { file_node_update(tree, child, 0, 1); child = child->next; } } } gboolean on_tree_motion_notify_event(GtkWidget * widget, GdkEventMotion * event, gpointer user_data ATTR_UNUSED) { int row, column; file_node_t* node; if (!gtk_clist_get_selection_info(GTK_CLIST(widget), (int) event->x, (int) event->y, &row, &column)) { filetips_show(NULL, event->x_root, event->y_root, NULL); return FALSE; } if (row < 0) return FALSE; node = gtk_clist_get_row_data(GTK_CLIST(widget), row); if (!node || !node->file) return FALSE; filetips_show(widget, event->x_root, event->y_root, node->file); return FALSE; } gboolean on_tree_leave_notify_event(GtkWidget * widget ATTR_UNUSED, GdkEventCrossing* event, gpointer user_data ATTR_UNUSED) { filetips_show(NULL, event->x_root, event->y_root, NULL); return FALSE; } void file_tree_release_page(file_tree_t* tree) { if (tree->signal[0] >= 0) gtk_signal_disconnect(GTK_OBJECT(tree->ctree), tree->signal[0]); tree->signal[0] = -1; if (tree->signal[1] >= 0) gtk_signal_disconnect(GTK_OBJECT(tree->search_entry), tree->signal[1]); tree->signal[1] = -1; if (tree->signal[2] >= 0) gtk_signal_disconnect(GTK_OBJECT(tree->clist), tree->signal[2]); tree->signal[2] = -1; if (tree->signal[3] >= 0) gtk_signal_disconnect(GTK_OBJECT(tree->clist), tree->signal[3]); tree->signal[3] = -1; if (tree->signal[4] >= 0) gtk_signal_disconnect(GTK_OBJECT(tree->clist), tree->signal[4]); tree->signal[4] = -1; if (tree->signal[5] >= 0) gtk_signal_disconnect(GTK_OBJECT(tree->button[0]), tree->signal[5]); tree->signal[5] = -1; if (tree->signal[6] >= 0) gtk_signal_disconnect(GTK_OBJECT(tree->button[1]), tree->signal[6]); tree->signal[6] = -1; } void popup_position(GtkMenu * menu, gint * x, gint * y, gpointer user_data); static void on_time_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { file_tree_t* tree = FILE_TREE(popup_tree); if (GTK_CHECK_MENU_ITEM(menuitem)->active) { file_tree_show(tree, tree->show_mime, GPOINTER_TO_INT(user_data)); } } void deactivate_auto_afk(); void on_file_tree_files1_clicked(GtkButton * button ATTR_UNUSED, gpointer user_data) { GtkWidget *popup; GtkWidget *item[MEDIA_SIZE+1]; file_tree_t* tree = user_data; int i1, i2; char str[1024]; char str2[1024]; int cnt; GSList *radio_group; deactivate_auto_afk(); popup_tree = tree; popup = gtk_menu_new(); if (!tree->files) { item[0] = gtk_menu_item_new_with_label("No files"); gtk_widget_show(item[0]); gtk_widget_set_sensitive(item[0], FALSE); gtk_container_add(GTK_CONTAINER(popup), item[0]); gtk_menu_popup(GTK_MENU(popup), NULL, NULL, (GtkMenuPositionFunc) popup_position, button, 1, 0); return; } ////////////////// radio_group = NULL; cnt = 0; i1 = tree->show_mime; for (i2 = 0; i2 <= 3; i2++) { if (tree->fci[i1][i2] == 0) { item[i2] = NULL; continue; } print_size(str2, tree->fsi[i1][i2]); sprintf(str, "%s: %d (%.1f%%) %s (%.1f%%)", TNames(i2), tree->fci[i1][i2], (double)(tree->fci[i1][i2])/ (double)(tree->fci[i1][3])*100., str2, tree->fsi[i1][i2]/tree->fsi[i1][3]*100.); if (i2 == 3) { item[i2] = gtk_menu_item_new(); gtk_widget_show(item[i2]); gtk_container_add(GTK_CONTAINER(popup), item[i2]); gtk_widget_set_sensitive(item[i2], FALSE); } item[i2] = gtk_radio_menu_item_new_with_label (radio_group, str); radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (item[i2])); gtk_widget_show(item[i2]); if (tree->show_time == i2) gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item[i2]), TRUE); gtk_container_add(GTK_CONTAINER(popup), item[i2]); cnt++; } for (i2 = 0; i2 <= 3; i2++) { if (item[i2]) gtk_signal_connect(GTK_OBJECT(item[i2]), "activate", GTK_SIGNAL_FUNC(on_time_activate), (void *) i2); } gtk_menu_popup(GTK_MENU(popup), NULL, NULL, (GtkMenuPositionFunc) popup_position, button, 1, 0); } static void on_mime_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { file_tree_t* tree = FILE_TREE(popup_tree); if (GTK_CHECK_MENU_ITEM(menuitem)->active) { file_tree_show(tree, GPOINTER_TO_INT(user_data), tree->show_time); } } void on_file_tree_files2_clicked(GtkButton * button ATTR_UNUSED, gpointer user_data) { GtkWidget *popup; GtkWidget *item[MEDIA_SIZE+1]; file_tree_t* tree = user_data; int i1, i2; char str[1024]; char str2[1024]; int cnt; GSList *radio_group; deactivate_auto_afk(); popup_tree = tree; popup = gtk_menu_new(); if (!tree->files) { item[0] = gtk_menu_item_new_with_label("No files"); gtk_widget_show(item[0]); gtk_widget_set_sensitive(item[0], FALSE); gtk_container_add(GTK_CONTAINER(popup), item[0]); gtk_menu_popup(GTK_MENU(popup), NULL, NULL, (GtkMenuPositionFunc) popup_position, button, 1, 0); return; } radio_group = NULL; cnt = 0; i2 = tree->show_time; for (i1 = 0; i1 <= MEDIA_SIZE; i1++) { if (tree->fci[i1][i2] == 0) { item[i1] = NULL; continue; } print_size(str2, tree->fsi[i1][i2]); sprintf(str, "%s: %d (%.1f%%) %s (%.1f%%)", MNames(i1), tree->fci[i1][i2], (double)(tree->fci[i1][i2])/ (double)(tree->fci[MEDIA_SIZE][i2])*100., str2, tree->fsi[i1][i2]/tree->fsi[MEDIA_SIZE][i2]*100.); if (i1 == MEDIA_SIZE) { item[i1] = gtk_menu_item_new(); gtk_widget_show(item[i1]); gtk_container_add(GTK_CONTAINER(popup), item[i1]); gtk_widget_set_sensitive(item[i1], FALSE); } item[i1] = gtk_radio_menu_item_new_with_label (radio_group, str); radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (item[i1])); gtk_widget_show(item[i1]); if (tree->show_mime == i1) gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item[i1]), TRUE); gtk_container_add(GTK_CONTAINER(popup), item[i1]); cnt++; } for (i1 = 0; i1 <= MEDIA_SIZE; i1++) { if (item[i1]) gtk_signal_connect(GTK_OBJECT(item[i1]), "activate", GTK_SIGNAL_FUNC(on_mime_activate), (void *) i1); } gtk_menu_popup(GTK_MENU(popup), NULL, NULL, (GtkMenuPositionFunc) popup_position, button, 1, 0); }