?? ptk-dir-tree.c
字號:
/** C Implementation: ptk-dir-tree** Description: *** Author: Hong Jen Yee (PCMan) <pcman.tw (AT) gmail.com>, (C) 2006** Copyright: See COPYING file that comes with this distribution**/#include "ptk-dir-tree.h"#include <gdk/gdk.h>#include <glib/gi18n.h>#include <string.h>#include "vfs-file-info.h"#include "vfs-file-monitor.h"#include "glib-mem.h"struct _PtkDirTreeNode{ VFSFileInfo* file; PtkDirTreeNode* children; int n_children; VFSFileMonitor* monitor; int n_expand; PtkDirTreeNode* parent; PtkDirTreeNode* next; PtkDirTreeNode* prev; PtkDirTreeNode* last; PtkDirTree* tree; /* FIXME: This is a waste of memory :-( */};static void ptk_dir_tree_init ( PtkDirTree *tree );static void ptk_dir_tree_class_init ( PtkDirTreeClass *klass );static void ptk_dir_tree_tree_model_init ( GtkTreeModelIface *iface );static void ptk_dir_tree_drag_source_init ( GtkTreeDragSourceIface *iface );static void ptk_dir_tree_drag_dest_init ( GtkTreeDragDestIface *iface );static void ptk_dir_tree_finalize ( GObject *object );static GtkTreeModelFlags ptk_dir_tree_get_flags ( GtkTreeModel *tree_model );static gint ptk_dir_tree_get_n_columns ( GtkTreeModel *tree_model );static GType ptk_dir_tree_get_column_type ( GtkTreeModel *tree_model, gint index );static gboolean ptk_dir_tree_get_iter ( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path );static GtkTreePath *ptk_dir_tree_get_path ( GtkTreeModel *tree_model, GtkTreeIter *iter );static void ptk_dir_tree_get_value ( GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value );static gboolean ptk_dir_tree_iter_next ( GtkTreeModel *tree_model, GtkTreeIter *iter );static gboolean ptk_dir_tree_iter_children ( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent );static gboolean ptk_dir_tree_iter_has_child ( GtkTreeModel *tree_model, GtkTreeIter *iter );static gint ptk_dir_tree_iter_n_children ( GtkTreeModel *tree_model, GtkTreeIter *iter );static gboolean ptk_dir_tree_iter_nth_child ( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n );static gboolean ptk_dir_tree_iter_parent ( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child );static gint ptk_dir_tree_node_compare( PtkDirTree* tree, PtkDirTreeNode* a, PtkDirTreeNode* b );static void ptk_dir_tree_insert_child( PtkDirTree* tree, PtkDirTreeNode* parent, const char* file_path, const char* name );static void ptk_dir_tree_delete_child( PtkDirTree* tree, PtkDirTreeNode* child );/* signal handlers */static void on_file_monitor_event ( VFSFileMonitor* fm, VFSFileMonitorEvent event, const char* file_name, gpointer user_data );static PtkDirTreeNode* ptk_dir_tree_node_new( PtkDirTree* tree, PtkDirTreeNode* parent, const char* path, const char* base_name );static void ptk_dir_tree_node_free( PtkDirTreeNode* node );static GObjectClass* parent_class = NULL;static GType column_types[ N_DIR_TREE_COLS ];GType ptk_dir_tree_get_type ( void ){ static GType type = 0; if ( G_UNLIKELY( !type ) ) { static const GTypeInfo type_info = { sizeof ( PtkDirTreeClass ), NULL, /* base_init */ NULL, /* base_finalize */ ( GClassInitFunc ) ptk_dir_tree_class_init, NULL, /* class finalize */ NULL, /* class_data */ sizeof ( PtkDirTree ), 0, /* n_preallocs */ ( GInstanceInitFunc ) ptk_dir_tree_init }; static const GInterfaceInfo tree_model_info = { ( GInterfaceInitFunc ) ptk_dir_tree_tree_model_init, NULL, NULL }; static const GInterfaceInfo drag_src_info = { ( GInterfaceInitFunc ) ptk_dir_tree_drag_source_init, NULL, NULL }; static const GInterfaceInfo drag_dest_info = { ( GInterfaceInitFunc ) ptk_dir_tree_drag_dest_init, NULL, NULL }; type = g_type_register_static ( G_TYPE_OBJECT, "PtkDirTree", &type_info, ( GTypeFlags ) 0 ); g_type_add_interface_static ( type, GTK_TYPE_TREE_MODEL, &tree_model_info ); g_type_add_interface_static ( type, GTK_TYPE_TREE_DRAG_SOURCE, &drag_src_info ); g_type_add_interface_static ( type, GTK_TYPE_TREE_DRAG_DEST, &drag_dest_info ); } return type;}void ptk_dir_tree_init ( PtkDirTree *tree ){ PtkDirTreeNode* child; tree->root = g_slice_new0( PtkDirTreeNode ); tree->root->tree = tree; tree->root->n_children = 1; child = ptk_dir_tree_node_new( tree, tree->root, "/", "/" ); vfs_file_info_set_disp_name( child->file, _("File System") ); tree->root->children = child; /* child = ptk_dir_tree_node_new( tree, tree->root, g_get_home_dir(), NULL ); vfs_file_info_set_name( child->file, g_get_home_dir() ); tree->root->children->next = child; */ /* Random int to check whether an iter belongs to our model */ tree->stamp = g_random_int();}void ptk_dir_tree_class_init ( PtkDirTreeClass *klass ){ GObjectClass * object_class; parent_class = ( GObjectClass* ) g_type_class_peek_parent ( klass ); object_class = ( GObjectClass* ) klass; object_class->finalize = ptk_dir_tree_finalize;}void ptk_dir_tree_tree_model_init ( GtkTreeModelIface *iface ){ iface->get_flags = ptk_dir_tree_get_flags; iface->get_n_columns = ptk_dir_tree_get_n_columns; iface->get_column_type = ptk_dir_tree_get_column_type; iface->get_iter = ptk_dir_tree_get_iter; iface->get_path = ptk_dir_tree_get_path; iface->get_value = ptk_dir_tree_get_value; iface->iter_next = ptk_dir_tree_iter_next; iface->iter_children = ptk_dir_tree_iter_children; iface->iter_has_child = ptk_dir_tree_iter_has_child; iface->iter_n_children = ptk_dir_tree_iter_n_children; iface->iter_nth_child = ptk_dir_tree_iter_nth_child; iface->iter_parent = ptk_dir_tree_iter_parent; column_types [ COL_DIR_TREE_ICON ] = GDK_TYPE_PIXBUF; column_types [ COL_DIR_TREE_DISP_NAME ] = G_TYPE_STRING; column_types [ COL_DIR_TREE_INFO ] = G_TYPE_POINTER;}void ptk_dir_tree_drag_source_init ( GtkTreeDragSourceIface *iface ){ /* FIXME: Unused. Will this cause any problem? */}void ptk_dir_tree_drag_dest_init ( GtkTreeDragDestIface *iface ){ /* FIXME: Unused. Will this cause any problem? */}void ptk_dir_tree_finalize ( GObject *object ){ PtkDirTree *tree = ( PtkDirTree* ) object; if( tree->root ) ptk_dir_tree_node_free( tree->root ); /* must chain up - finalize parent */ ( * parent_class->finalize ) ( object );}PtkDirTree *ptk_dir_tree_new (){ PtkDirTree * tree; tree = ( PtkDirTree* ) g_object_new ( PTK_TYPE_DIR_TREE, NULL ); return tree;}GtkTreeModelFlags ptk_dir_tree_get_flags ( GtkTreeModel *tree_model ){ g_return_val_if_fail ( PTK_IS_DIR_TREE( tree_model ), ( GtkTreeModelFlags ) 0 ); return GTK_TREE_MODEL_ITERS_PERSIST;}gint ptk_dir_tree_get_n_columns ( GtkTreeModel *tree_model ){ return N_DIR_TREE_COLS;}GType ptk_dir_tree_get_column_type ( GtkTreeModel *tree_model, gint index ){ g_return_val_if_fail ( PTK_IS_DIR_TREE( tree_model ), G_TYPE_INVALID ); g_return_val_if_fail ( index < G_N_ELEMENTS( column_types ) && index >= 0, G_TYPE_INVALID ); return column_types[ index ];}static PtkDirTreeNode* get_nth_node( PtkDirTreeNode* parent, int n ){ PtkDirTreeNode* node; if ( n >= parent->n_children || n < 0 ) return NULL; node = parent->children; while( n > 0 && node ) { node = node->next; --n; } return node;}gboolean ptk_dir_tree_get_iter ( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path ){ PtkDirTree *tree; gint *indices, i, depth; PtkDirTreeNode* node; g_assert(PTK_IS_DIR_TREE(tree_model)); g_assert(path!=NULL); tree = PTK_DIR_TREE(tree_model); if( !tree || !tree->root ) return FALSE; indices = gtk_tree_path_get_indices(path); depth = gtk_tree_path_get_depth(path); node = tree->root; for( i = 0; i < depth; ++i ) { node = get_nth_node( node, indices[i] ); if( !node ) return FALSE; } /* We simply store a pointer in the iter */ iter->stamp = tree->stamp; iter->user_data = node; iter->user_data2 = NULL; iter->user_data3 = NULL; /* unused */ return TRUE;}static int get_node_index( PtkDirTreeNode* parent, PtkDirTreeNode* child ){ PtkDirTreeNode* node; int i; if( !parent || !child ) return -1; for( i = 0, node = parent->children; node; node = node->next ) { if( node == child ) { return i; } ++i; } return -1;}GtkTreePath *ptk_dir_tree_get_path ( GtkTreeModel *tree_model, GtkTreeIter *iter ){ PtkDirTreeNode* node; GtkTreePath* path; int i; PtkDirTree* tree = PTK_DIR_TREE(tree_model); g_return_val_if_fail (tree, NULL); g_return_val_if_fail (iter->stamp == tree->stamp, NULL); g_return_val_if_fail (iter != NULL, NULL); g_return_val_if_fail (iter->user_data != NULL, NULL); path = gtk_tree_path_new(); node = (PtkDirTreeNode*)iter->user_data; g_return_val_if_fail( node->parent != NULL, (GtkTreePath *)(-1) ); while( node != tree->root ) { i = get_node_index( node->parent, node ); if( i == -1 ) { gtk_tree_path_free( path ); return NULL; } gtk_tree_path_prepend_index( path, i ); node = node->parent; } return path;}void ptk_dir_tree_get_value ( GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value ){ PtkDirTree* tree = PTK_DIR_TREE(tree_model); VFSFileInfo* info; GdkPixbuf* icon; PtkDirTreeNode* node; g_return_if_fail (PTK_IS_DIR_TREE (tree_model)); g_return_if_fail (iter != NULL); g_return_if_fail (column < G_N_ELEMENTS(column_types) ); g_value_init (value, column_types[column] ); node = (PtkDirTreeNode*) iter->user_data; g_return_if_fail ( node != NULL ); info = node->file; switch(column) { case COL_DIR_TREE_ICON: if( G_UNLIKELY( !info ) ) return; icon = vfs_file_info_get_small_icon( info ); if( icon ) { g_value_set_object( value, icon ); gdk_pixbuf_unref( icon ); } break; case COL_DIR_TREE_DISP_NAME: if( G_LIKELY( info ) ) g_value_set_string( value, vfs_file_info_get_disp_name(info) ); else g_value_set_string( value, _("No Sub Folder") ); break; case COL_DIR_TREE_INFO: if( G_UNLIKELY( !info ) ) return; vfs_file_info_ref( info ); g_value_set_pointer( value, info ); break; }}gboolean ptk_dir_tree_iter_next ( GtkTreeModel *tree_model, GtkTreeIter *iter ){ PtkDirTreeNode* node; PtkDirTree* tree; g_return_val_if_fail (PTK_IS_DIR_TREE (tree_model), FALSE); if (iter == NULL || iter->user_data == NULL) return FALSE; tree = PTK_DIR_TREE(tree_model); node = (PtkDirTreeNode *) iter->user_data; /* Is this the last child in the parent node? */ if ( ! node->next ) return FALSE; iter->stamp = tree->stamp; iter->user_data = node->next; iter->user_data2 = NULL; iter->user_data3 = NULL; return TRUE;}gboolean ptk_dir_tree_iter_children ( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent ){ PtkDirTree* tree; PtkDirTreeNode* parent_node; PtkDirTreeNode* node; g_return_val_if_fail ( parent == NULL || parent->user_data != NULL, FALSE ); g_return_val_if_fail ( PTK_IS_DIR_TREE ( tree_model ), FALSE ); tree = PTK_DIR_TREE( tree_model ); if ( parent ) parent_node = (PtkDirTreeNode*)parent->user_data; else { /* parent == NULL is a special case; we need to return the first top-level row */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -