diff --git a/library/Trait/Tree.php b/application/modules/admin/controllers/Pcdm4BrowserController.php
similarity index 82%
rename from library/Trait/Tree.php
rename to application/modules/admin/controllers/Pcdm4BrowserController.php
index 93aa996a77afa01d223aa081609fc33ee93f3dbe..890487f1a472395a69ac7b64667c3d451dc78a39 100644
--- a/library/Trait/Tree.php
+++ b/application/modules/admin/controllers/Pcdm4BrowserController.php
@@ -20,7 +20,8 @@
  */
 
 
-trait Trait_Tree {
-  abstract public function getParent();
-  abstract public function getChildren();
+class Admin_Pcdm4BrowserController extends ZendAfi_Controller_Action {
+  public function getPlugins() {
+    return ['ZendAfi_Controller_Plugin_ResourceDefinition_Codification_Pcdm4'];
+  }
 }
\ No newline at end of file
diff --git a/library/Class/CodifPcdm4.php b/library/Class/CodifPcdm4.php
index f150873e038899a3fa0a74f3447ef9d11c313ad2..e41d627762b2b211bad190b3ca6fddee9c437a29 100644
--- a/library/Class/CodifPcdm4.php
+++ b/library/Class/CodifPcdm4.php
@@ -20,30 +20,133 @@
  */
 
 class Class_CodifPcdm4Loader extends Storm_Model_Loader {
-// ----------------------------------------------------------------
-// Rend le libelle ou le code si le libelle est vide
-// ----------------------------------------------------------------
+
+  public function findParentOf($instance) {
+    if (!$instance || $instance->isNew())
+      return;
+
+    if ('' === $parent_id = substr($instance->getId(), 0, -1))
+      return;
+
+    return Class_CodifPcdm4::find($parent_id);
+  }
+
+
+  public function findLeavesOfBy($instance, $params = []) {
+    return array_filter($instance->getChildren($params),
+                        function ($child)
+                        {
+                          return !$child->hasChildren();
+                        });
+  }
+
+
+  public function findNodesOfBy($instance, $params = []) {
+    return array_filter($instance->getChildren($params),
+                        function ($child)
+                        {
+                          return $child->hasChildren();
+                        });
+  }
+
+
+  public function findChildrenOfBy($instance, $params = []) {
+    if(!$instance)
+      return [];
+
+    $id = $instance->getId();
+    $length = $instance->isNew()
+      ? ' = 1'
+      : ' = ' . (strlen($id) + 1);
+
+    $where = sprintf('id_pcdm4 like "%s%%" and LENGTH(id_pcdm4) %s',
+                     $id,
+                     $length);
+
+    $params = array_merge(['order' => 'id_pcdm4'],
+                          $params,
+                          ['where' => $where]);
+
+    return Class_CodifPcdm4::findAllBy($params);
+  }
+
+
+  public function recursiveNumberOfChildrenOf($instance) {
+    if($instance->isNew())
+      return 0;
+
+    $id = $instance->getId();
+    $where = sprintf('id_pcdm4 like "%s%%" and LENGTH(id_pcdm4) > %s',
+                     $id,
+                     strlen($id));
+
+    return Class_CodifPcdm4::countBy(['where' => $where]);
+  }
+
+
   public function getLibelle($indice) {
-    return (($pcdm4 = Class_CodifPcdm4::find($indice)) && $pcdm4->getLibelle())
-            ? $pcdm4->getLibelle()
-            : Class_CodifPcdm4::formatIndice($indice);
+    return ($pcdm4 = Class_CodifPcdm4::find($indice))
+      ? $pcdm4->getLibelle()
+      : Class_CodifPcdm4::formatIndice($indice);
+  }
+
+
+  public function formatIndice($indice) {
+    return (strlen($indice) < 2)
+      ? $indice
+      : substr($indice, 0, 1) . '.' . substr($indice, 1);
+  }
+
+
+  public function filtreIndice($indice) {
+    $indice=trim($indice);
+    if(strlen($indice) > 1 and substr($indice,1,1) != ".")
+      return "";
+
+    $new="";
+    for($i=0; $i<strlen($indice); $i++) {
+      $car = substr($indice, $i, 1);
+      if ($car >= "0" and $car<="9")
+        $new .= $car;
+    }
+
+    return $new;
+  }
+
+
+  public function getIndices($pere) {
+    $sql = Zend_Registry::get('sql');
+    if ($pere == "root")
+       $liste=$sql->fetchAll("select * from codif_pcdm4 where LENGTH(id_pcdm4)=1 order by id_pcdm4");
+    else {
+      $long=strlen($pere)+1;
+      $req="select * from codif_pcdm4 where id_pcdm4 like '$pere%' and LENGTH(id_pcdm4)=$long order by id_pcdm4";
+      $liste =$sql->fetchAll($req);
+    }
+    return $liste;
+  }
+
+
+  public function root() {
+    return new Class_CodifPcdm4;
   }
 }
 
+
+
+
 class Class_CodifPcdm4 extends Storm_Model_Abstract {
+  use Trait_Facetable, Trait_TreeNode;
 
   const CODE_FACETTE = 'P';
 
-  protected $_table_name = 'codif_pcdm4';
-  protected $_table_primary = 'id_pcdm4';
-  protected $_loader_class = 'Class_CodifPcdm4Loader';
+  protected
+    $_table_name = 'codif_pcdm4',
+    $_table_primary = 'id_pcdm4',
+    $_loader_class = 'Class_CodifPcdm4Loader';
+
 
-  // ----------------------------------------------------------------
-// Rend une liste pour un champ suggestion
-// ----------------------------------------------------------------
-  public function getListeSuggestion($recherche,$mode,$limite_resultat)
-  {
-    // Lancer la recherche
+  public function getListeSuggestion($recherche,$mode,$limite_resultat) {
     $new = '';
     if($mode=="1")
     {
@@ -55,7 +158,6 @@ class Class_CodifPcdm4 extends Storm_Model_Abstract {
 
     $resultat=fetchAll($req);
 
-    // Mettre l'indice et le libelle
     if(!$resultat) return false;
     foreach($resultat as $enreg)
     {
@@ -65,46 +167,11 @@ class Class_CodifPcdm4 extends Storm_Model_Abstract {
     return $liste;
   }
 
-// ----------------------------------------------------------------
-// Rend une liste d'indices par niveau
-// ----------------------------------------------------------------
-  static function getIndices($pere)
-  {
-    $sql = Zend_Registry::get('sql');
-    if ($pere == "root")
-       $liste=$sql->fetchAll("select * from codif_pcdm4 where LENGTH(id_pcdm4)=1 order by id_pcdm4");
-    else {
-      $long=strlen($pere)+1;
-      $req="select * from codif_pcdm4 where id_pcdm4 like '$pere%' and LENGTH(id_pcdm4)=$long order by id_pcdm4";
-      $liste =$sql->fetchAll($req);
-    }
-    return $liste;
-  }
-// ----------------------------------------------------------------
-// Ponctue un indice pcdm4
-// ----------------------------------------------------------------
-  static function formatIndice($indice)
-  {
-    if(strlen($indice)< 2) return $indice;
-    $new=substr($indice,0,1).".".substr($indice,1);
-    return $new;
-  }
-// ----------------------------------------------------------------
-// Analyse et rend l'indice s'il est valide
-// ----------------------------------------------------------------
-  static function filtreIndice($indice)
-  {
-    $indice=trim($indice);
-    if(strlen($indice) > 1 and substr($indice,1,1) != ".") return "";
-    $new="";
-    for($i=0; $i<strlen($indice); $i++)
-    {
-      $car=$indice[$i];
-      if($car >="0" and $car<="9") $new.=$car;
-    }
-    return $new;
-  }
-
-}
 
-?>
\ No newline at end of file
+  public function getLibelle() {
+    $libelle = parent::_get('libelle');
+    return $libelle
+      ? $libelle
+      : $this->getLoader()->formatIndice($this->getId());
+  }
+}
\ No newline at end of file
diff --git a/library/Class/CodifTypeDoc.php b/library/Class/CodifTypeDoc.php
index 8b8ad871a3d709fcb73e74769a340f4c2933332c..5aef7d14fbb63054d4c5122950f112248d7c6231 100644
--- a/library/Class/CodifTypeDoc.php
+++ b/library/Class/CodifTypeDoc.php
@@ -35,7 +35,8 @@ class Class_CodifTypeDoc extends Storm_Model_Abstract {
   protected $_table_primary = 'type_doc_id';
   protected $_default_attribute_values = ['bibliotheques' => '',
                                           'annexes' => '',
-                                          'sections' => ''];
+                                          'sections' => '',
+                                          'famille_id' => ''];
 
   protected static $_libelles = [self::INCONNU => 'Non identifié',
                                  self::LIVRE => 'Livre',
diff --git a/library/Class/ListViewModeDescription/Pcdm4.php b/library/Class/ListViewModeDescription/Pcdm4.php
new file mode 100644
index 0000000000000000000000000000000000000000..295e06a6625bbc6609eb7615a252457a98db770f
--- /dev/null
+++ b/library/Class/ListViewModeDescription/Pcdm4.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_ListViewModeDescription_Pcdm4 extends Class_ListViewModeDescription {
+
+  public function __construct($context) {
+    parent::__construct($context);
+    if(!$this->_context->getOrder())
+      $this->_context->setOrder('id_pcdm4');
+  }
+
+
+  protected function _getLabel() {
+    return $this->_('PCDM4');
+  }
+
+
+  protected function _getController() {
+    return 'pcdm4-browser';
+  }
+
+
+  protected function _getModel() {
+    return null === $this->_context->getParentId()
+      ? Class_CodifPcdm4::root()
+      : Class_CodifPcdm4::find($this->_context->getParentId());
+  }
+
+
+  protected function _getSearchColumns() {
+    return ['libelle',
+            'id_pcdm4'];
+  }
+
+
+  public function describeCategoriesIn($description, $list_view_mode) {
+    return $description
+      ->addColumn($this->_('PCDM4'), ['attribute' => 'libelle',
+                                        'callback' => $list_view_mode->renderCategoryClosure()])
+      ->addColumn($this->_('Code facette'), 'facet_code');
+  }
+
+
+  public function describeItemsIn($description, $list_view_mode) {
+    return $description
+      ->addColumn($this->_('PCDM4'), ['attribute' => 'libelle',
+                                      'callback' => $list_view_mode->renderItemClosure()])
+      ->addColumn($this->_('Code facette'), ['attribute' => 'facet_code',
+                                             'sort_attribute' => 'id_pcdm4'])
+      ->setSorterServer();
+  }
+}
\ No newline at end of file
diff --git a/library/Trait/TreeNode.php b/library/Trait/TreeNode.php
index f35e89f486f22618ec46df6c0c4371f1b49f4bf8..265bcb563ed17fb051c988bf7a76b82a4c66d2f9 100644
--- a/library/Trait/TreeNode.php
+++ b/library/Trait/TreeNode.php
@@ -20,7 +20,6 @@
  */
 
 trait Trait_TreeNode {
-  use Trait_Tree;
 
   public static $PATH_SEPARATOR = '/';
 
@@ -89,20 +88,35 @@ trait Trait_TreeNode {
   }
 
 
-  public function getLeaves() {
-    ;
+  public function getParent() {
+    return $this->getLoader()->findParentOf($this);
   }
 
 
-  public function getNodes() {
-    ;
+  public function getLeaves($params = []) {
+    if($this->isNew())
+      return [];
+
+    return $this->getLoader()->findLeavesOfBy($this, $params);
+  }
+
+
+  public function getNodes($params = []) {
+    return $this->getLoader()->findNodesOfBy($this, $params);
+  }
+
+
+  public function getChildren($params = []) {
+    return $this->getLoader()->findChildrenOfBy($this, $params);
   }
 
 
   public function numberOfLeaves() {
+    return count($this->getLeaves());
   }
 
 
   public function recursiveNumberOfChildren() {
+    return $this->getLoader()->recursiveNumberOfChildrenOf($this);
   }
 }
\ No newline at end of file
diff --git a/library/Trait/TreeViewableCategorie.php b/library/Trait/TreeViewableCategorie.php
index 56dd3940c382eb36870a40a6d5a476f80fbe3aa3..e18d9ce944144e07062dfef7a8ae69436332a526 100644
--- a/library/Trait/TreeViewableCategorie.php
+++ b/library/Trait/TreeViewableCategorie.php
@@ -20,7 +20,6 @@
  */
 
 trait Trait_TreeViewableCategorie {
-  use Trait_Tree;
 
   /**
    * @return bool
diff --git a/library/Trait/TreeViewableItem.php b/library/Trait/TreeViewableItem.php
index eb01606fe2c3cf5c2aea1f85705014a4a66cdce7..ef7d466ca2ed5ec0de7d273cffa453d875d69545 100644
--- a/library/Trait/TreeViewableItem.php
+++ b/library/Trait/TreeViewableItem.php
@@ -20,7 +20,6 @@
  */
 
 trait Trait_TreeViewableItem {
-  use Trait_Tree;
 
   public function getBib() {
     return $this->getCategorie()
diff --git a/library/ZendAfi/Controller/Action/Helper/AbstractListViewMode.php b/library/ZendAfi/Controller/Action/Helper/AbstractListViewMode.php
index 892c7802fb67f62f24acc3c0d2d797e6f6c97126..a5f2b345238bb8d2db5fb6489216a16bc3c2b6c3 100644
--- a/library/ZendAfi/Controller/Action/Helper/AbstractListViewMode.php
+++ b/library/ZendAfi/Controller/Action/Helper/AbstractListViewMode.php
@@ -63,7 +63,7 @@ abstract class ZendAfi_Controller_Action_Helper_AbstractListViewMode extends Zen
     $url = $this->_view->url($this->renderCategoryUrlParams($model), null, true);
 
     $label = Class_Admin_Skin::current()->renderActionIconOn('category', $this->_view)
-      . $model->$attrib;
+      . $model->callGetterByAttributeName($attrib);
 
     $count = '';
 
@@ -94,7 +94,7 @@ abstract class ZendAfi_Controller_Action_Helper_AbstractListViewMode extends Zen
 
 
   protected function _renderItem($model, $attrib) {
-    $value = call_user_func([$model, 'get' . Storm_Inflector::camelize($attrib)]);
+    $value = $model->callGetterByAttributeName($attrib);
     if (!$this->isSearching())
       return $value;
 
diff --git a/library/ZendAfi/Controller/Action/Helper/CodificationListViewMode.php b/library/ZendAfi/Controller/Action/Helper/CodificationListViewMode.php
index 6b575147760edeaf75aa110bd86df3ee368280ce..dad1b0188e1529b53826090396607ed0e200774b 100644
--- a/library/ZendAfi/Controller/Action/Helper/CodificationListViewMode.php
+++ b/library/ZendAfi/Controller/Action/Helper/CodificationListViewMode.php
@@ -52,6 +52,10 @@ class ZendAfi_Controller_Action_Helper_CodificationListViewMode
                           ->setLibelle($this->_('Langues'))
                           ->setController('language-browser'),
 
+                          (new Class_CodifPcdm4)
+                          ->setLibelle($this->_('PCDM4'))
+                          ->setController('pcdm4-browser'),
+
                           (new Class_CodifSection)
                           ->setLibelle($this->_('Sections'))
                           ->setController('section-browser'),
@@ -68,8 +72,8 @@ class ZendAfi_Controller_Action_Helper_CodificationListViewMode
                           ->setLibelle($this->_('Thesaurus'))
                           ->setController('thesauri'),
 
-                          (new Class_CodifTypeDoc)
-                          ->setLibelle($this->_('Types de documents'))
+                          (new Class_TypeDoc)
+                          ->setLabel($this->_('Types de documents'))
                           ->setController('doctype-browser')];
   }
 
diff --git a/library/ZendAfi/Controller/Plugin/ResourceDefinition/Codification/Pcdm4.php b/library/ZendAfi/Controller/Plugin/ResourceDefinition/Codification/Pcdm4.php
new file mode 100644
index 0000000000000000000000000000000000000000..2b34cf827016f46d6475c842783dfca4495cd261
--- /dev/null
+++ b/library/ZendAfi/Controller/Plugin/ResourceDefinition/Codification/Pcdm4.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class ZendAfi_Controller_Plugin_ResourceDefinition_Codification_Pcdm4
+  extends ZendAfi_Controller_Plugin_ResourceDefinition_Codification_Abstract {
+
+  public function getDefinitions() {
+    return
+      ['model' => ['class' => 'Class_CodifPcdm4',
+                   'name' => 'pcdm4',
+                   'order' => 'libelle'],
+
+       'listViewMode' => 'Class_ListViewModeDescription_Pcdm4',
+
+       'actions' => ['index' => ['title' => $this->_('Parcourir la codification PCDM4')]]];
+  }
+}
\ No newline at end of file
diff --git a/tests/scenarios/CodificationBrowser/CodificationBrowserTest.php b/tests/scenarios/CodificationBrowser/CodificationBrowserTest.php
index 69bd6051bd0b2a55793b58df779845e19a201036..1f751f9aae3b19a48e854d918c4ec267c7ab98ef 100644
--- a/tests/scenarios/CodificationBrowser/CodificationBrowserTest.php
+++ b/tests/scenarios/CodificationBrowser/CodificationBrowserTest.php
@@ -42,7 +42,8 @@ class CodificationBrowserIndexDispatchTest extends Admin_AbstractControllerTestC
             ['genre-browser', 'Genres'],
             ['subject-browser', 'Sujets et matières'],
             ['tag-browser', 'Tags'],
-            ['doctype-browser', 'Types de documents']];
+            ['doctype-browser', 'Types de documents'],
+            ['pcdm4-browser', 'PCDM4']];
   }
 
 
@@ -200,3 +201,12 @@ class CodificationBrowserDoctypeSimpleIndexTest extends CodificationBrowserSimpl
     $_model = 'Class_TypeDoc',
     $_attribs = ['id' => 1, 'label' => 'Livres'];
 }
+
+
+
+class CodificationBrowserPCDM4SimpleIndexTest extends CodificationBrowserSimpleIndexTestCase {
+  protected
+    $_controller = 'pcdm4-browser',
+    $_model = 'Class_CodifPcdm4',
+    $_attribs = ['id' => '0', 'libelle' => 'Histoire'];
+}
diff --git a/tests/scenarios/Pcdm4Browser/Pcdm4BrowserTest.php b/tests/scenarios/Pcdm4Browser/Pcdm4BrowserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..117f236e09b41fff5072688ca1a3820aec2750d0
--- /dev/null
+++ b/tests/scenarios/Pcdm4Browser/Pcdm4BrowserTest.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Pcdm4BrowserIndexChildrenTest extends Admin_AbstractControllerTestCase{
+  protected $_storm_default_to_volatile = true;
+
+  public function setUp() {
+    parent::setUp();
+    $mainstream = $this->fixture('Class_CodifPcdm4',
+                                 ['id' => '0',
+                                  'libelle' => 'Mainstream']);
+
+    $notso = $this->fixture('Class_CodifPcdm4',
+                            ['id' => '01',
+                             'libelle' => 'Not so mainstream']);
+
+    $notsoleaf = $this->fixture('Class_CodifPcdm4',
+                            ['id' => '02',
+                             'libelle' => 'Not so leaf']);
+
+    $this->onLoaderOfModel('Class_CodifPcdm4')
+         ->whenCalled('find')->with('0')->answers($mainstream)
+         ->whenCalled('findParentOf')->with($mainstream)->answers(null)
+         ->whenCalled('findNodesOfBy')->with($mainstream, [])->answers([$notso])
+         ->whenCalled('recursiveNumberOfChildrenOf')->with($notso)->answers(1)
+
+         ->whenCalled('findLeavesOfBy')
+         ->with($mainstream, ['limitPage' => [null, 25],
+                              'order' => 'id_pcdm4'])
+         ->answers([$notsoleaf])
+
+         ->whenCalled('findLeavesOfBy')
+         ->with($mainstream, [])
+         ->answers([$notsoleaf])
+
+         ->beStrict();
+
+    $this->dispatch('/admin/pcdm4-browser/index/parent_id/0', true);
+  }
+
+
+  /** @test */
+  public function mainstreamShouldBeDisplay() {
+    $this->assertXpathContentContains('//a', 'Mainstream', $this->_response->getBody());
+  }
+
+
+  /** @test */
+  public function notsoShouldBeInTable() {
+    $this->assertXpathContentContains('//td', 'Not so mainstream');
+  }
+
+
+  /** @test */
+  public function notsoleafShouldBeInTable() {
+    $this->assertXpathContentContains('//td', 'Not so leaf');
+  }
+}