📄 ptk-dir-tree.c
字号:
parent_node = tree->root; } /* No rows => no first row */ if ( parent_node->n_children == 0 ) return FALSE; /* Set iter to first item in tree */ iter->stamp = tree->stamp; iter->user_data = parent_node->children; iter->user_data2 = iter->user_data3 = NULL; return TRUE;}gboolean ptk_dir_tree_iter_has_child ( GtkTreeModel *tree_model, GtkTreeIter *iter ){ PtkDirTreeNode* node; g_return_val_if_fail( iter != NULL, FALSE ); node = (PtkDirTreeNode*)iter->user_data; return node->n_children != 0;}gint ptk_dir_tree_iter_n_children ( GtkTreeModel *tree_model, GtkTreeIter *iter ){ PtkDirTreeNode* node; PtkDirTree* tree; g_return_val_if_fail ( PTK_IS_DIR_TREE ( tree_model ), -1 ); tree = PTK_DIR_TREE( tree_model ); /* special case: if iter == NULL, return number of top-level rows */ if ( !iter ) node = tree->root; else node = (PtkDirTreeNode*)iter->user_data; g_return_val_if_fail ( node != NULL, -1 ); return node->n_children;}gboolean ptk_dir_tree_iter_nth_child ( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n ){ PtkDirTreeNode* parent_node; PtkDirTreeNode* node; PtkDirTree* tree; g_return_val_if_fail (PTK_IS_DIR_TREE (tree_model), FALSE); tree = PTK_DIR_TREE(tree_model); if( G_LIKELY(parent) ) { parent_node = ( PtkDirTreeNode* )parent->user_data; g_return_val_if_fail( parent_node, FALSE ); } else { /* special case: if parent == NULL, set iter to n-th top-level row */ parent_node = tree->root; } if( n >= parent_node->n_children || n < 0 ) return FALSE; node = get_nth_node( parent_node, n ); iter->stamp = tree->stamp; iter->user_data = node; iter->user_data2 = iter->user_data3 = NULL; return TRUE;}gboolean ptk_dir_tree_iter_parent ( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child ){ PtkDirTreeNode* node; PtkDirTree* tree; g_return_val_if_fail( iter != NULL && child != NULL, FALSE ); tree = PTK_DIR_TREE( tree_model ); node = (PtkDirTreeNode*)child->user_data; if( G_LIKELY( node->parent != tree->root ) ) { iter->user_data = node->parent; iter->user_data2 = iter->user_data3 = NULL; return TRUE; } return FALSE;}gint ptk_dir_tree_node_compare( PtkDirTree* tree, PtkDirTreeNode* a, PtkDirTreeNode* b ){ VFSFileInfo* file1 = a->file; VFSFileInfo* file2 = b->file; int ret; if( ! file1 || !file2 ) return 0; /* FIXME: UTF-8 strings should not be treated as ASCII when sorted */ ret = g_ascii_strcasecmp( vfs_file_info_get_disp_name(file2), vfs_file_info_get_disp_name(file1) ); return ret;}PtkDirTreeNode* ptk_dir_tree_node_new( PtkDirTree* tree, PtkDirTreeNode* parent, const char* path, const char* base_name ){ PtkDirTreeNode* node; node = g_slice_new0( PtkDirTreeNode ); node->tree = tree; node->parent = parent; if( path ) { node->file = vfs_file_info_new(); vfs_file_info_get( node->file, path, base_name ); node->n_children = 1; node->children = ptk_dir_tree_node_new( tree, node, NULL, NULL ); node->last = node->children; } return node;}void ptk_dir_tree_node_free( PtkDirTreeNode* node ){ PtkDirTreeNode* child; if( node->file ) vfs_file_info_unref( node->file ); for( child = node->children; child; child = child->next ) ptk_dir_tree_node_free( child ); if( node->monitor ) { vfs_file_monitor_remove( node->monitor, &on_file_monitor_event, node ); } g_slice_free( PtkDirTreeNode, node );}static char* dir_path_from_tree_node( PtkDirTree* tree, PtkDirTreeNode* node ){ GSList* names = NULL, *l; const char* name; int len; char* dir_path, *p; if( !node ) return NULL; while( node != tree->root ) { if( !node->file || ! (name = vfs_file_info_get_name( node->file )) ) { g_slist_free( names ); return NULL; } names = g_slist_prepend( names, name ); node = node->parent; } for( len = 1, l = names; l; l = l->next ) len += strlen((char*)l->data) + 1; dir_path = g_malloc( len ); for( p = dir_path, l = names; l; l = l->next ) { name = (char*)l->data; len = strlen( name ); memcpy( p, name, len * sizeof(char) ); p += len; if( l->next && strcmp( name, "/" ) ) { *p = '/'; ++p; } } *p = '\0'; g_slist_free( names ); return dir_path;}void ptk_dir_tree_insert_child( PtkDirTree* tree, PtkDirTreeNode* parent, const char* file_path, const char* name ){ PtkDirTreeNode *child_node; PtkDirTreeNode *node; GtkTreeIter it; GtkTreePath* tree_path; child_node = ptk_dir_tree_node_new( tree, parent, file_path, name ); for( node = parent->children; node; node = node->next ) { if( ptk_dir_tree_node_compare( tree, child_node, node ) >= 0 ) break; } if( node ) { if( node->prev ) { child_node->prev = node->prev; node->prev->next = child_node; } child_node->next = node; if( node == parent->children ) parent->children = child_node; node->prev = child_node; } else { if( parent->children ) { child_node->prev = parent->last; parent->last->next = child_node; parent->last = child_node; } else { parent->children = parent->last = child_node; } } ++parent->n_children; it.stamp = tree->stamp; it.user_data = child_node; it.user_data2 = it.user_data3 = NULL; tree_path = ptk_dir_tree_get_path( GTK_TREE_MODEL(tree), &it ); gtk_tree_model_row_inserted( GTK_TREE_MODEL(tree), tree_path, &it ); gtk_tree_model_row_has_child_toggled( GTK_TREE_MODEL(tree), tree_path, &it ); gtk_tree_path_free( tree_path );}void ptk_dir_tree_delete_child( PtkDirTree* tree, PtkDirTreeNode* child ){ GtkTreeIter child_it; GtkTreePath* tree_path; PtkDirTreeNode* parent; if( !child ) return; child_it.stamp = tree->stamp; child_it.user_data = child; child_it.user_data2 = child_it.user_data3 = NULL; tree_path = ptk_dir_tree_get_path( GTK_TREE_MODEL(tree), &child_it ); gtk_tree_model_row_deleted( GTK_TREE_MODEL(tree), tree_path ); gtk_tree_path_free( tree_path ); parent = child->parent; --parent->n_children; if( child == parent->children ) parent->children = parent->last = child->next; else if( child == parent->last ) parent->last = child->prev; if( child->prev ) child->prev->next = child->next; if( child->next ) child->next->prev = child->prev; ptk_dir_tree_node_free( child ); if( parent->n_children == 0 ) { /* add place holder */ ptk_dir_tree_insert_child( tree, parent, NULL,NULL ); }}void ptk_dir_tree_expand_row ( PtkDirTree* tree, GtkTreeIter* iter, GtkTreePath *tree_path ){ PtkDirTreeNode *node, *place_holder; GtkTreeIter child; GDir *dir; char *path, *file_path; const char *name=NULL; node = (PtkDirTreeNode*)iter->user_data; ++node->n_expand; if( node->n_expand > 1 || node->n_children > 1 ) return; place_holder = node->children; path = dir_path_from_tree_node( tree, node ); dir = g_dir_open( path, 0, NULL ); if( dir ) { node->monitor = vfs_file_monitor_add( path, &on_file_monitor_event, node ); while( (name = g_dir_read_name( dir )) ) { file_path = g_build_filename( path, name, NULL ); if( g_file_test( file_path, G_FILE_TEST_IS_DIR ) ) { ptk_dir_tree_insert_child( tree, node, file_path, name ); } g_free( file_path ); } g_dir_close( dir ); if( node->n_children > 1 ) { ptk_dir_tree_delete_child( tree, place_holder ); } } g_free( path );}void ptk_dir_tree_collapse_row ( PtkDirTree* tree, GtkTreeIter* iter, GtkTreePath *path ){ PtkDirTreeNode *node, *child, *next; node = (PtkDirTreeNode*)iter->user_data; --node->n_expand; /* cache nodes containing more than 128 children */ /* FIXME: Is this useful? The nodes containing childrens with 128+ children are still not cached. */ if( node->n_children > 128 || node->n_expand > 0 ) return; if( node->n_children > 0 ) { /* place holder */ if( node->n_children == 1 && ! node->children->file ) return; if( G_LIKELY( node->monitor ) ) { vfs_file_monitor_remove( node->monitor, &on_file_monitor_event, node ); node->monitor = NULL; } for( child = node->children; child; child = next ) { next = child->next; ptk_dir_tree_delete_child( tree, child ); } }}char* ptk_dir_tree_get_dir_path( PtkDirTree* tree, GtkTreeIter* iter ){ g_return_val_if_fail( iter->user_data != NULL, NULL ); return dir_path_from_tree_node( tree, (PtkDirTreeNode*)iter->user_data );}static PtkDirTreeNode* find_node( PtkDirTreeNode* parent, const char* name ){ PtkDirTreeNode* child; for( child = parent->children; child; child = child->next ) { if( G_LIKELY(child->file ) && 0 == strcmp( vfs_file_info_get_name(child->file), name ) ) { return child; } } return NULL;}void on_file_monitor_event ( VFSFileMonitor* fm, VFSFileMonitorEvent event, const char* file_name, gpointer user_data ){ PtkDirTreeNode* node = (PtkDirTreeNode*)user_data; PtkDirTreeNode* child; GtkTreeIter it; GtkTreePath* tree_path; char* file_path; g_return_if_fail( node ); GDK_THREADS_ENTER(); child = find_node( node, file_name ); switch( event ) { case VFS_FILE_MONITOR_CREATE: if( G_LIKELY( !child ) ) { /* remove place holder */ if( node->n_children == 1 && !node->children->file ) child = node->children; else child = NULL; file_path = g_build_filename( fm->path, file_name, NULL ); if( g_file_test( file_path, G_FILE_TEST_IS_DIR ) ) { ptk_dir_tree_insert_child( node->tree, node, fm->path, file_name ); if( child ) ptk_dir_tree_delete_child( node->tree, child ); } g_free( file_path ); } break; case VFS_FILE_MONITOR_DELETE: if( G_LIKELY( child ) ) { ptk_dir_tree_delete_child( node->tree, child ); } break; case VFS_FILE_MONITOR_CHANGE: if( G_LIKELY( child && child->file ) ) { file_path = g_build_filename( fm->path, file_name, NULL ); if( ! g_file_test( file_path, G_FILE_TEST_IS_DIR ) ) { g_free( file_path ); break; } vfs_file_info_get( child->file, file_path, file_name ); g_free( file_path ); it.stamp = node->tree->stamp; it.user_data = child; it.user_data2 = it.user_data3 = NULL; tree_path = ptk_dir_tree_get_path(GTK_TREE_MODEL(node->tree), &it); gtk_tree_model_row_changed( GTK_TREE_MODEL( node->tree ), tree_path, &it ); gtk_tree_model_row_has_child_toggled( GTK_TREE_MODEL( node->tree ), tree_path, &it ); gtk_tree_path_free( tree_path ); } break; } GDK_THREADS_LEAVE();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -