01 May 2013 - After the site upgrade, all passwords were reset and you will need to ask the site for a login reset on your first connection.

TreeViewPhpModel class - an easy way to build visual tree with GtkTreeView widget

What ?

Building a list for php-gtk2 using the complete framework is really complex task. When you only need to display a data tree and collect user selection, please, use this class. It very easy to use, no need to take care of complex GtkTreeView classes.

TreeView PHP model example

How

here is a simple example using this class :

<?php
error_reporting
(E_ALL);

include_once(
'TreeViewPhpModel.php');

# describe tree here :
$user_model = array(
 
"languages" => array("php", "c", "java"),
 
"methods" => array(
   
"Object Oriented",
   
"Procedural"
 
),
 
"red",
 
"blue",
 
"green"
);

$treeview = new TreeViewPhpModel();
$treeview->set_model($user_model);
$treeview->connect('changed',
 
'treeview_selection_changed', $treeview);
$treeview->expand_all();

$window = new GtkWindow();
$window->connect_simple('destroy', array('Gtk','main_quit'));
$window->set_size_request( 250, 400 );      # set window size
$window->set_position(Gtk::WIN_POS_CENTER); # place window to screen center
$window->set_title("TreeViewPhpModel - user model in php");
$window->add($treeview);

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

function
treeview_selection_changed($signal, $context, $tv) {
 
# echo "selection : {$context['key']} | {$context['value']}\n";
 
$tv->set_title("your selection : " . $context['value']);
  echo
"key = {$context['key']} ; val = {$context['value']}\n";

  switch(
$context['key']) {
    case
'green' :
     
# make what you need to do here
     
break;
  }
}
?>

PhpGtkDirectoryTree example

You can build more complex models using PHP syntax.

  • use array to create sub-arrays
  • you can provide a key and a litteral value that could be translated : use syntaxe : "key" => "value"
  • you can also use special syntaxe : $model = array("key1|value1", "key2|value2")

here is a more complex model example :

$user_model = array(
  "lang|languages" => array(
    "php"=> array(
      "extensions" => array(
        "snmp",
        "gtk" => array(
          "GtkTreeview",
          "GtkList",
          "GtkEntry",
          "GtkLabel"
        ),
        "mysql",
        "sqlite|SQLiteDatabase" => array(
          "constructor|__construct",
          "fetch",
          "fetchAll",
          "next",
        ),
        "image"
      )
    ),
    "c|c language",
    "c++|C++"
  ),
  "meth|methods" => array(
    "oo|Oject Oriented",
    "procedural" => "Procedural"
  )
);

Class

here is complete class source code :

<?php
error_reporting
(E_ALL);

/**
* TreeViewPhpModel class - the purpose of this class  is
* to populate a GtkTreeModel from an php array,
* to build a flat or tree list.
*
* - this class uses a GtkTreeView as main renderer,
* - try to be GtkTreeView externally but is a GtkVbox,
*    (some methods and signals are similar).
*
* public methods    : __construct(), connect(), set_model(),
*         select_key(), select_iter(), unselect_iter(),
*         expand_all(), collapse_all(), set_title()
* protected methods : build(), add_signals(), selection_changed(),
*        find_model(), iter_childs(), model_populate()
* private methods   : user_model_to_text()
*
*/

# for this class include : http://php.classes.free.fr/php/gtk/gnope/
# and install  Gnope_FileExplorer
# other link : http://www.php-gtk.eu/apps/gnope_file_explorer
require_once('Gnope/FileExplorer/Signal.php');

<?
php
class TreeViewPhpModel extends GtkVbox {
 
# internal Gtk widgets set for GtkTreeView managment.
 
protected $user_model;
  protected
$model;
  protected
$scrolled_win;
  protected
$treeview;
  protected
$column;

 
  protected
$title;     # title in TreeRow
 
protected $signal;    # signal managed by this class

  /**
   *  TreeViewPhpModel::__construct($user_model = null)
   *
   *  - create a TreeViewPhpModel widget
   *  - you can in option pass list|tree model
   *
   */
 
function __construct($user_model = null) {
   
parent::__construct();
   
$this->user_model = $user_model;
   
$this->build();
   
$this->add_signals();  # register to GtkSignal for GtkWidgets

    # signals managment for this class.
   
$this->signal = new Gnope_FileExplorer_Signal();

    if (
$this->user_model != null)
     
$this->render($this->user_model);
  }


 
/**
   * protected function build()
   * build widget hierarchy
   *   widget tree :
   *   $this (Gnope_FileExplorer_DirectoryTree extends from GtkVbox)
   *     $this->scolled_win (GtkScrolledWindow)
   *       $this->treeview (GtkTreeView)
   */
 
protected function build() {
   
# store file, path
   
$this->model = new GtkTreeStore(Gtk::TYPE_STRING, 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);

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

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

 
/**
   * protected function add_signals() - internal : add signals to
   * GtkTreeView when items are selected
   */
 
protected function add_signals() {
   
$this->treeview->get_selection()->connect('changed',
      array(
$this,'selection_changed'));
  }

 
/**
   * public function connect($signal, $method, $user_data=null)
   *
   * register to signal (actualy : changed).
   */
 
public function connect($signal, $method, $user_data=null) {
    return
$this->signal->connect($signal, $method, $user_data);
  }

 
/**
   * public function set_model($php_model)
   *
   * given a structured php-array, populate GtkTreeviewModel according to given data.
   *
   * example :
   *
   * $treeview = new TreeViewUserModel()
   * $model = array( "red", "blue", "yellow");
   * $treeview->set_model($model);
   *
   * -> create a flat list entry without subtree
   *
   * creating recursive tree :
   * - you just have to create sub arrays :
   *
   * $model = array(
   *  "colors" => array( "yellow", "blue"),
   *  "month"  => array("january", "february")
   *  "single-item"
   *  ),
   *
   * you can create (key, values) pairs in model :
   *     * key should be short (for programming),
   *    * value should be the literal form
   *
   *    - using "|" separator :
   *        -> $model = array("1|yellow", "2|blue", "days|The days" => array(...));
   *    - using standard php construct :
   *        -> $model = array( "1" => "yellow", "2" => "blue");
   */
 
public function set_model($user_model) {
   
$this->user_model = $user_model;
   
# $txt = $this->user_model_to_text($user_model);
    # echo "$txt\n";

   
$this->model->clear();
   
$this->model_populate($user_model, $node=null);
  }

 
/**
   * public function selection_changed (should be protected, but Signal class can't call)
   *
   * - called when user select a new item in list
   * - automaticaly called at creation because firt item is selected
   */
 
public function selection_changed() {
    list(
$tree_store, $iter_path_array) =
     
$this->treeview->get_selection()->get_selected_rows();

    if (
count($iter_path_array) == 0)
      return;

   
# single selection mode - remove array form for iter_path
   
$iter_path = $iter_path_array[0];

   
$iter = $this->model->get_iter($iter_path);
   
$key = $this->model->get_value($iter, 1);
   
$value = $this->model->get_value($iter, 0);
   
$context = array(
     
'iter'      => $iter,
     
'iter_path' => $iter_path,
     
'model'     => $this->model,
     
'treeview'  => $this->treeview,
     
'key'       => $key,
     
'value'     => $value
   
);

   
$this->signal->emmit('changed', $context);
  }

 
/**
   * public function select_key($key)
   * select (highligt) item in list containing $key (text value):
   *
   * - return false if key not found
   * - return true if key is found
   */
 
public function select_key($key) {
   
$status = $this->model_find($key, $this->model, null);
    if (
$status !== false) {
     
$this->select_iter($status);
      return
false;
    }
    return
true;
  }

 
/**
   * public function select_iter($iter)
   *
   * - highlight item in the treeview list given by iter
   * - $iter should be a GtkTreeIter
   */
 
public function select_iter($iter) {
   
$this->treeview->get_selection()->select_iter($iter);
  }

 
/**
   * public function unselect_iter($iter)
   *
   * - unselect (unhighlight) item in the treeview list given by iter
   * - $iter should be a GtkTreeIter
   *
   */
 
public function unselect_iter($iter) {
   
$this->treeview->get_selection()->unselect_iter($iter);
  }

 
/**
   *  protected function model_find($key_to_find, $model, $iter=null)
   *
   *  - given a $key, try to find the node containing this key
   *  - return iter for that search
   *  - or false;
   *
   */
 
protected function model_find($key_to_find, $model, $iter=null) {
    if (
$iter != null) {
     
$key = $model->get_value($iter, 1);
      if (
$key_to_find == $key)
        return
$iter;
    }

   
$childs = $this->iter_childs($model, $iter);
    foreach(
$childs as $child) {
     
$res = $this->model_find($key_to_find, $model, $child);
      if (
$res != null)
        return
$res;
      }

    return
false;
  }

  function
iter_childs($model, $iter) {
    if (
$iter != null) {
      if (!
$model->iter_has_child($iter))
        return array();

     
$list = array();
     
$count = $model->iter_n_children($iter);
      for(
$i=0 ; $i<$count; $i++)
       
$list[] = $model->iter_nth_child($iter, $i);

      return
$list;
    } else {
     
$iter = $model->get_iter_first();
     
$list = array();
     
$list[] = $iter;
      while (
null != ($iter = $model->iter_next($iter)))
       
$list[] = $iter;
      return
$list;
    }
  }

 
/**
   * void protected function model_populate($model, $node=null)
   *
   * recursive method for pupulating GtkTreeviewModel,
   * - $model : an array containing list or tree to view,
   * - node : null for first call, contains current inserting node in recursion
   *
   */
 
protected function model_populate($model, $node = null) {
    if (!
is_array($model))
      return
false;

    foreach (
$model as $key=>$entry) {
      if (!
is_array($entry)){
        if (
preg_match('/(.+)\|(.+)/', $entry, $values)) {
         
$key = $values[1];
         
$entry = $values[2];
        }
      }
     
     
# current entry is an array with some sub_nodes :
      # create current node entry, and recurse sub array
     
if (is_array($entry)) {
      if (
preg_match('/(.+)\|(.+)/', $key, $values)) {
       
$key = $values[1];
       
$literal = $values[2];
      } else
       
$literal = $key;

     
$sub_node = $this->model->append($node, array($literal, $key));
     
$this->model_populate($entry, $sub_node);
    } else {
      if(!
is_int($key)){
       
$this->model->append($node, array($entry, $key));
      }
      else {
       
$this->model->append($node, array($entry, $entry));
        }
      }
    }
  }

 
# for debug purpose.
 
private function user_model_to_text($model, $level=0) {
    if (!
is_array($model))
      return
'';

   
$spacing = str_repeat('    ', $level);
   
$txt = '';

    foreach (
$model as $key=>$entry) {
      if (!
is_array($entry)) {
        if (
preg_match('/(.+)\|(.+)/', $entry, $values)) {
         
$key = $values[1];
         
$entry = $values[2];
        }
      }
      if (
is_array($entry)) {
       
$txt .=  "$spacing * $key\n";
       
$txt .= $this->model_to_text($entry, $level+1);
      } else {
        if (!
is_int($key))
         
$txt .= "$spacing - $key | $entry\n";
        else
         
$txt .= "$spacing - $entry\n";
      }
    }
    return
$txt;
  }

 
/**
   * public function expand_all()
   *
   * expand all nodes showing all list.
   *
   */
 
public function expand_all() {
   
$this->treeview->expand_all();
  }

 
/**
   * public function collapse_all()
   *
   * collapse all nodes showing only root-tree
   *
   */
 
public function collapse_all() {
   
$this->treeview->collapse_all();
  }

 
/**
   * public function set_title($title)
   *
   * set title in row head.
   *
   */
 
public function set_title($title){
   
$this->title = $title;
   
$this->column->set_title($title);
  }
}
?>

PřílohaVelikost
TreeViewPhpModel.php - class source code10.89 KB