PhpGtkDirectoryTree: displaying a directory tree

Displaying a directory tree with php-gtk is not really simple. But with a little help, you will be able to create a new Widget Tree based on GtkTreeView. You can create new widgets with php-gtk in a few lines of code. This task is far more involved with pure C/Gtk code.

Introduction

PhpGtkDirectoryTree example This class is named PhpGtkDirectoryTree. It is a composite widget inherited from GtkComposite widget tree. Because it is a widget, you can add it directly to a GtkWindow object.

A more complete version is available in Gnope repository ; this class is named : FileExplorer

Basic class usage

Here is a quick example displaying the directory tree for a UNIX directory. Windows users, please adapt $dir value.

<?php
# avoid bare errors - reports warning for stupid errors
error_reporting(E_ALL);

# our nice Tree widget class
require_once('PhpGtkDirectoryTree.class.php');

# main part - create a new Tree object and fill it with a directory tree
$tree = new PhpGtkDirectoryTree();
$dir = '/usr/share/doc';
$tree->open_directory($dir);
$tree->set_title($dir);

$window = new GtkWindow();
$window->connect_simple('destroy', array('Gtk','main_quit'));
$window->set_size_request(300, 600 );      # set window size
$window->set_position(Gtk::WIN_POS_CENTER); # place window to screen center
$window->set_title("TreeView directory display example");
$window->add($tree);

# display it
$window->show_all();
Gtk::main();
?>

Todo

  • read directory tree as needed, and not all at once upon creation ; opening a large directory tree when widget is opened (realized) may block Gtk mainloop and make some troubles in display and other features managed by mail loop : socket reading, timeout. So we really need to find a nicer way to open and read directories.
  • add event callbacks for selections and folder open-close : work in progress here and here again :-)
  • a complet class framework for directory browsing is available here : http://www.php-gtk.eu/apps/gnope_file_explorer

Class Code

<?php
error_reporting
(E_ALL);

# authors :
#
# * class : Marc Quinton - november 2006.
# * main php-gtk2 tricks from kksou :  http://www.kksou.com/php-gtk2/
#
# require php-gtk2
#

class PhpGtkDirectoryTree extends GtkVbox {
  protected
$model;
  protected
$scrolled_win;
  protected
$treeview;
  protected
$column;

  protected
$icon_folder_open;
  protected
$icon_folder_closed;

  protected
$title;
  protected
$trace;

  function
__construct() {
   
parent::__construct();

   
$this->icon_folder_open = 'folder_open.gif';
   
$this->icon_folder_closed = 'folder_closed.gif';

   
$this->trace = false;
   
$this->build();
  }

  function
build() {
   
$this->model = new GtkTreeStore(Gtk::TYPE_STRING);

   
$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);
   
# $this->treeview->set_size_request(400, 320);

    //set up treeview columns
   
$this->column = new GtkTreeViewColumn();

   
// for image
   
$cell_renderer = new GtkCellRendererPixbuf();
   
$this->column->pack_start($cell_renderer, false);

    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);

   
// 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
open_directory($folder) {
    if (!
is_dir($folder)) {
     
trigger_error("PhpGtkDirectoryTree : "
       
. "directory not found",
       
E_USER_WARNING);
      return
false;
    }
   
$this->model->clear();
   
$root = $folder;
   
$dir_list = array($root);
   
$nodes = array();
   
$nodes[$root] = null;

    while (
count($dir_list)>0) {
     
$dir = array_shift($dir_list);
     
$this->trace("folder = $dir\n");

     
// add the directories first
     
if ($handle = opendir($dir)) {
        while (
false !== ($file = readdir($handle))) {
          if (
$file != "." && $file != "..") {
           
$fullpath = $dir.'/'.$file;
            if (
is_dir($fullpath)) {
             
$nodes[$fullpath] = $this->model->append(
               
$nodes[$dir], array($file));
             
array_push($dir_list, $fullpath);
            }
          }
        }
       
closedir($handle);
      }

     
$num_files = 0;
     
// then add the files
     
if ($handle = opendir($dir)) {
        while (
false !== ($file = readdir($handle))) {
          if (
$file != "." && $file != "..") {
           
$fullpath = $dir.'/'.$file;
          if (!
is_dir($fullpath)) {
           
$nodes[$fullpath] = $this->model->append(
             
$nodes[$dir], array($file));
            ++
$num_files;
            }
          }
        }
       
closedir($handle);
      }

     
# FIXME : bug here when directory is empty (no files or only sub-directories)
     
if ($num_files==0)
       
$nodes[$fullpath] = $this->model->append(
         
$nodes[$dir], array(''));
    }
  }

  function
set_title($title) {
   
$this->title = $title;
   
$this->column->set_title($title);
  }

  function
trace($txt) {
    if (
$this->trace)
      echo
"$txt";
  }
}
?>

Class Internals

  • todo ...

Bugs

  • when reading a directory with only subdirectories (no files) or empty, there is a problem with modele tree ; tree is displayed with a blank entry.

Hints

  • you could get feedback for directory tree reading with trace() method. Just subclass PhpGtkDirectoryTree widget and display a feedback in a label widget, or perhaps in title part of PhpGtkDirectoryTree.

Copyright

Main of this class comes from great site from kksou. Please refer to his site for usage.

links