icon_folder_open = 'folder_open.gif'; $this->icon_folder_closed = 'folder_closed.gif'; $this->trace = true; $this->display_files = false; $this->set_icons_folders =true; $this->build(); $this->add_signals(); } function build(){ $this->model = new GtkTreeStore(Gtk::TYPE_STRING, Gtk::TYPE_STRING); # store file, path $this->scrolled_win = new GtkScrolledWindow(); $this->scrolled_win->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); $this->add($this->scrolled_win); // set up treeview $this->treeview = new GtkTreeView($this->model); $this->scrolled_win->add($this->treeview); //set up treeview columns $this->column = new GtkTreeViewColumn(); // for image $cell_renderer = new GtkCellRendererPixbuf(); $this->column->pack_start($cell_renderer, false); if($this->set_icons_folders) $this->set_icons_folders($cell_renderer); // for filename $cell_renderer = new GtkCellRendererText(); $this->column->pack_start($cell_renderer, true); $this->column->set_attributes($cell_renderer, 'text', 0); $this->treeview->append_column($this->column); } function set_icons_folders($cell_renderer){ if(file_exists($this->icon_folder_open) && file_exists($this->icon_folder_open)){ $cell_renderer->set_property('pixbuf-expander-open', GdkPixbuf::new_from_file($this->icon_folder_open)); $cell_renderer->set_property('pixbuf-expander-closed', GdkPixbuf::new_from_file($this->icon_folder_closed)); } else trigger_error("PhpGtkDirectoryTree : icon file for folder not found", E_USER_WARNING); } function add_signals(){ $signals = array( 'row-collapsed', # 'row-expanded', 'move-cursor', 'row-activated', 'select-cursor-parent', 'select-all', 'select-cursor-row', 'set-scroll-adjustments', 'start-interactive-search', 'test-collapse-row', # 'test-expand-row', 'toggle-cursor-row', 'unselect-all', 'columns-changed' ); foreach($signals as $sig) $this->treeview->connect_simple($sig, array($this,'treeview_signals'), $sig); # connect signal 'changed' to GtkTreeSelection object $this->treeview->get_selection()->connect('changed', array($this,'selection_changed')); $this->treeview->connect('test-expand-row', array($this,'treeview_test_expand'), null); $this->treeview->connect('row-expanded', array($this,'treeview_row_exanded'), null); $this->treeview->connect('row-activated', array($this,'treeview_row_activated'), null); } # http://www.pygtk.org/pygtk2reference/class-gtktreeview.html function treeview_signals($userdata){ $signal_type = $userdata; echo "treeview_signals ($userdata)\n"; switch($signal_type){ case 'row-activated': $selection = $this->treeview->get_selection(); # GTkTreeSelection if(is_object($selection)) echo "selection class : " . get_class($selection) . "\n"; break; } } function treeview_test_expand($treeview, $iter, $path, $userdata){ $file = $this->model->get_value($iter, 0); $path = $this->model->get_value($iter, 1); # echo "treeview_test_expand() - $path - $file\n"; # return true; $fullpath = $path . '/' . $file; if(!$this->has_subdirs($fullpath)) return true; else{ # need to populate node if needed $child_iter = $this->model->iter_children($iter); if($this->model->get_value($child_iter, 0) == null){ $this->model->remove($child_iter); $this->open_directory($fullpath, $iter, $_display_files=false, $_recurse_subdirs=false); } return false; } } function treeview_row_exanded($test){ # echo "treeview_row_expanded()\n"; # print_r($test); } function selection_changed($tree_selection){ # echo "selection changed\n"; # list($tree_store, $path) = $this->treeview->get_selection()->get_selected_rows(); # $this->model->foreach(array($this, 'selection_changed_iter')); $tree_selection->selected_foreach(array($this, 'selection_foreach')); } function selection_foreach($model, $item_path, $iter){ $file = $model->get_value($iter, 0); $path = $model->get_value($iter, 1); # auto expand or collapse row on user selection. if($this->treeview->row_expanded($item_path)) $this->treeview->collapse_row($item_path); else $this->treeview->expand_row($item_path, false); } function open_directory($folder, $node=null, $display_files=false, $recurse_subdirs=false){ if(!is_dir($folder)){ trigger_error("PhpGtkDirectoryTree : directory not found", E_USER_WARNING); return false; } if($node == null){ $this->model->clear(); # $node = $this->model->append(null); } $sub_nodes = array(); $dirs = $this->get_subdirs($folder); $files = $this->get_files($folder); foreach($dirs as $subdir){ $fullpath = $folder.'/'.$subdir; $sub_nodes[] = $sub_node = $this->model->append($node, array($subdir, $folder)); if($recurse_subdirs && $this->has_subdirs($fullpath)){ $this->open_directory($fullpath, $sub_node, $display_files, $recurse_subdirs); } else { # to show node as a subdirectory, need to add a empty subnode. $this->model->append($sub_node, array(null, null)); } } if($display_files){ foreach($files as $file){ $fullpath = $folder.'/'.$file; $this->model->append($node, array($file, $folder)); } } return true; } function has_subdirs($dir){ $subdirs = $this->get_subdirs($dir); if(count($subdirs) == 0) return false; return true; } function get_subdirs($dir, $sort=true){ $d = opendir($dir); if(!$d) return array(); $list = array(); while(($file = readdir($d)) !== false){ if($file != '.' && $file != '..'){ $fullpath = $dir . '/' . $file; if(is_dir($fullpath)) $list[] = $file; } } if($sort) $this->sort($list); return $list; } function get_files($dir, $sort=true){ $d = opendir($dir); if(!$d) return array(); $list = array(); while(($file = readdir($d)) !== false){ if($file != '.' && $file != '..'){ $fullpath = $dir . '/' . $file; if(!is_dir($fullpath)) $list[] = $file; } } if($sort) $this->sort($list); return $list; } function set_title($title){ $this->title = $title; $this->column->set_title($title); } function sort(&$array){ natcasesort($array); } function trace($txt){ if($this->trace) echo "$txt"; } function debug($txt, $obj){ if(is_object($obj)) echo "$txt : " . get_class($obj) . "\n"; else{ echo "$txt : " ; print_r($obj); } } } ?>