r21187: - Convert LdbBrowse to use TreeVirtual. This adds the following capabilities
authorDerrell Lipman <derrell@samba.org>
Tue, 6 Feb 2007 21:00:23 +0000 (21:00 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:44:44 +0000 (14:44 -0500)
  that Simo asked for:

  * One can now open a branch without selecting the row.  The previously
    selected row (if any) remains selected.

  * Selecting a row does not automatically open the branch.  That can be done
    by either clicking on the open/close button or pressing Enter while that
    row is selected.

  * The entire tree can now be disabled.  In LdbBrowse, the fsm is configured
    to disable the tree during each remote procedure call, so that a pile of
    requests don't get queued during RPC.

  The most obvious flaw with TreeVirtual right now, is that the tree does not
  properly resize (or even initially size itself) to its container.  Fixing
  that is my next task.  It's actually a generic Table issue that people have
  been asking for for ages: having columns resize themselves automagically.

webapps/swat/source/class/swat/module/ldbbrowse/Fsm.js
webapps/swat/source/class/swat/module/ldbbrowse/Gui.js

index cb62c1f976ad941440ac697f33ab433f0d880f81..f595864383eb7049f7474abcecd5906ee8c1a3fa 100644 (file)
@@ -100,7 +100,7 @@ qx.Proto.buildFsm = function(module)
           // populate the attribute/value table.
           "changeSelection":
           {
-            "tree:manager" :
+            "tree" :
               "Transition_Idle_to_AwaitRpcResult_via_tree_selection_changed",
 
             "dbName":
@@ -224,24 +224,28 @@ qx.Proto.buildFsm = function(module)
       "ontransition" :
         function(fsm, event)
         {
-          var parent = event.getData();
-          var hierarchy = parent.getHierarchy(new Array());
+          // Get the tree object
+          var tree = fsm.getObject("tree");
 
-          parent.debug("Requesting children...");
+          // Get the node on which the event occurred
+          var node = event.getData();
+
+          // Obtain the full hierarchy for this node
+          var hierarchy = tree.getHierarchy(node.nodeId);
+
+          tree.debug("Requesting children for node id " + node.nodeId + ": " +
+                     hierarchy.join("/") + "...");
 
           // Strip off the root node
           hierarchy.shift();
 
-          // Get the tree object
-          var tree = fsm.getObject("tree");
-
           // Determine the children.  Differs depending on root or otherwise
           var attributes;
           var scope;
           var baseDN;
             
           // If parent is the root...
-          if (parent == tree)
+          if (node.parentNodeId == 0)
           {
             // ... then we want the defaultNamingContext, ...
             attributes = [ "defaultNamingContext", "namingContexts" ];
@@ -290,7 +294,7 @@ qx.Proto.buildFsm = function(module)
           request.setUserData("requestType", "tree_open");
 
           // We'll also need some of our parameters
-          request.setUserData("parent", parent);
+          request.setUserData("parentNode", node);
           request.setUserData("attributes", attributes);
         }
     });
@@ -313,22 +317,26 @@ qx.Proto.buildFsm = function(module)
       "predicate" :
         function(fsm, event)
         {
-          var element = event.getData()[0];
-          var hierarchy = element.getHierarchy(new Array());
+          // Get the tree object
+          var tree = fsm.getObject("tree");
+
+          // Get the list of selected nodes.  We're in single-selection mode,
+          // so there will be only one of them.
+          var nodes = event.getData();
+          var node = nodes[0];
+
+          var hierarchy = tree.getHierarchy(node.nodeId);
 
           // Strip off the root node
           hierarchy.shift();
 
-          // Get the tree object
-          var tree = fsm.getObject("tree");
-
           // If element is the root...
-          if (element == tree)
+          if (node.parentNodeId == 0)
           {
             // ... then just clear out the attribute/value table.
             var tableModel = fsm.getObject("tableModel:browse");
             tableModel.setData([]);
-            return null;        // don't search additional transitionis
+            return null;        // don't search additional transitions
           }
 
           return true;
@@ -337,15 +345,19 @@ qx.Proto.buildFsm = function(module)
       "ontransition" :
         function(fsm, event)
         {
-          var element = event.getData()[0];
-          var hierarchy = element.getHierarchy(new Array());
+          // Get the tree object
+          var tree = fsm.getObject("tree");
+
+          // Get the list of selected nodes.  We're in single-selection mode,
+          // so there will be only one of them.
+          var nodes = event.getData();
+          var node = nodes[0];
+
+          var hierarchy = tree.getHierarchy(node.nodeId);
 
           // Strip off the root node
           hierarchy.shift();
 
-          // Get the tree object
-          var tree = fsm.getObject("tree");
-
           // Determine the children.  Differs depending on root or otherwise
           var attributes;
           var scope;
@@ -437,7 +449,7 @@ qx.Proto.buildFsm = function(module)
     // populate the attribute/value table.
     "changeSelection":
     {
-      "tree:manager" : 
+      "tree" : 
         qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED,
 
       "dbName":
index eb3e6add280c6fe7a06d2d4ff853daea3870e303..99ceb7ccd69d32eb59ca9cecd1ada1d13225f38f 100644 (file)
@@ -319,34 +319,42 @@ qx.Proto._buildPageBrowse = function(module, page)
                spacing: 10
            });
 
-  // Create a tree row structure for the tree root
-  var trsInstance = qx.ui.treefullcontrol.TreeRowStructure.getInstance();
-  var trs = trsInstance.standard(module.dbFile);
-
   // Create the tree and set its characteristics
-  var tree = new qx.ui.treefullcontrol.Tree(trs);
+  var tree = new qx.ui.treevirtual.TreeVirtual(["Browse"]);
   tree.set({
-               backgroundColor: 255,
-               border: qx.renderer.border.BorderPresets.getInstance().inset,
-               overflow: "auto",
-               height: "1*",
-               open: false,
-               alwaysShowPlusMinusSymbol: true
+             backgroundColor: 255,
+             border : qx.renderer.border.BorderPresets.getInstance().thinInset,
+             overflow: "auto",
+             width: "100%",
+             height: "1*",
+             alwaysShowOpenCloseSymbol: true
            });
 
-  // All subtrees will use this root node's event listeners.  Create an event
-  // listener for an open while empty.
-  tree.addEventListener("treeOpenWhileEmpty", fsm.eventListener, fsm);
+  // We've only got one column, so we don't need cell focus indication.
+  tree.setCellFocusAttributes({ backgroundColor : "transparent" });
+
+  // This needs to become automatic!
+  tree.setColumnWidth(0, 200);
+
+  // We only have one column.  We don't need the column visibility button
+  tree.setColumnVisibilityButtonVisible(false);
 
-  // All subtrees will use this root node's event listeners.  Create an event
-  // listener for selection changed, to populate attribute/value table
-  tree.getManager().addEventListener("changeSelection",
-                                     fsm.eventListener,
-                                     fsm);
+  // Get the data model
+  var dataModel = tree.getDataModel();
 
-  // We'll be receiving events on the tree object, so save its friendly name
-  fsm.addObject("tree", tree);
-  fsm.addObject("tree:manager", tree.getManager());
+  // Add the database file as the first node
+  dataModel.addBranch(null, module.dbFile, false);
+
+  // We're finished adding nodes.
+  dataModel.setData();
+
+  // Create event listeners
+  tree.addEventListener("treeOpenWhileEmpty", fsm.eventListener, fsm);
+  tree.addEventListener("changeSelection", fsm.eventListener, fsm);
+
+  // We'll be receiving events on the tree object, so save its friendly name,
+  // and cause the tree to be disabled during remote procedure calls.
+  fsm.addObject("tree", tree, "swat.main.fsmUtils.disable_during_rpc");
 
   // Add the tree to the vlayout.
   vlayout.add(tree);
@@ -492,62 +500,60 @@ qx.Proto._displaySearchResults = function(module, rpcRequest)
 qx.Proto._displayTreeOpenResults = function(module, rpcRequest)
 {
   var t;
-  var trs;
   var child;
+  var fsm = module.fsm;
+
+  // Get the tree object
+  var tree = fsm.getObject("tree");
+  var dataModel = tree.getDataModel();
 
   // Obtain the result object
   var result = rpcRequest.getUserData("result").data;
 
   // We also need some of the original parameters passed to the request
-  var parent = rpcRequest.getUserData("parent");
+  var parentNode = rpcRequest.getUserData("parentNode");
   var attributes = rpcRequest.getUserData("attributes");
 
   // Any children?
   if (! result || result["length"] == 0)
   {
-    // Nope.  Allow parent's expand/contract button to be removed
-    parent.setAlwaysShowPlusMinusSymbol(false);
+    // Nope.  Remove parent's expand/contract button.
+    dataModel.setState(parentNode.nodeId, { bHideOpenClose : true });
+    dataModel.setData();
     return;
   }
 
   // base object, add naming contexts to the root
   if ((result.length == 1) &&
       ((result[0]["dn"] == "") ||
-       (result[0]["dn"].toLowerCase() == "cn=rootdse"))) {
-
+       (result[0]["dn"].toLowerCase() == "cn=rootdse")))
+  {
     defnc = result[0]["defaultNamingContext"];
 
     // Build a tree row for the defaultNamingContext
-    if (defnc) {
-      trs = qx.ui.treefullcontrol.TreeRowStructure.getInstance().standard(defnc);
-      // This row is a "folder" (it can have children)
-      t = new qx.ui.treefullcontrol.TreeFolder(trs);
-      t.setAlwaysShowPlusMinusSymbol(true);
-
-      // Add this row to its parent
-      parent.add(t);
+    if (defnc)
+    {
+      dataModel.addBranch(parentNode.nodeId, defnc, false);
     }
 
     var ncs = result[0]["namingContexts"];
 
-    // If it's multi-valued (type is an array) we have other naming contexts to show
-    if (typeof(ncs) == "object") {
-      
-      for (var i = 0; i < ncs.length; i++) {
-        if (ncs[i] != defnc) { //skip default naming context
-          trs = qx.ui.treefullcontrol.TreeRowStructure.getInstance().standard(ncs[i]);
-          // This row is a "folder" (it can have children)
-          t = new qx.ui.treefullcontrol.TreeFolder(trs);
-          t.setAlwaysShowPlusMinusSymbol(true);
-  
-          // Add this row to its parent
-          parent.add(t);
+    // If it's multi-valued (type is an array) we have other naming contexts
+    // to show
+    if (typeof(ncs) == "object")
+    {
+      for (var i = 0; i < ncs.length; i++)
+      {
+        if (ncs[i] != defnc)
+        {
+          //skip default naming context
+          dataModel.addBranch(parentNode.nodeId, ncs[i], false);
         }
       }
     }
   }
-  else {
-
+  else
+  {
     for (var i = 0; i < result.length; i++)
     {
       var name;
@@ -557,17 +563,12 @@ qx.Proto._displayTreeOpenResults = function(module, rpcRequest)
       name = child["dn"].split(",")[0];
   
       // Build a standard tree row
-      trs = qx.ui.treefullcontrol.TreeRowStructure.getInstance().standard(name);
-  
-      // This row is a "folder" (it can have children)
-      t = new qx.ui.treefullcontrol.TreeFolder(trs);
-      t.setAlwaysShowPlusMinusSymbol(true);
-  
-      // Add this row to its parent
-      parent.add(t);
+      dataModel.addBranch(parentNode.nodeId, name, false);
     }
-
   }
+
+  // Cause the tree changes to be rendered
+  dataModel.setData();
 };
 
 qx.Proto._displayLdbmodBaseChanged = function(module, rpcRequest)
@@ -594,11 +595,14 @@ qx.Proto._displayTreeSelectionChangedResults = function(module, rpcRequest)
   // Obtain the result object
   var result = rpcRequest.getUserData("result").data;
 
+  var tree = fsm.getObject("tree");
+  var dataModel = tree.getDataModel();
+
   // If we received an empty list, ...
   if (result == null)
   {
     // ... then just clear the attribute/value table.
-    tableModel.setData([ ]);
+    dataModel.setData([ ]);
     return;
   }