summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--swat/apps/swat/source/class/swat/main/Main.js9
-rw-r--r--swat/apps/swat/source/class/swat/module/AbstractModule.js30
-rw-r--r--swat/apps/swat/source/class/swat/module/AbstractModuleFsm.js30
-rw-r--r--swat/apps/swat/source/class/swat/module/Module.js30
-rw-r--r--swat/apps/swat/source/class/swat/module/documentation/Documentation.js3
-rw-r--r--swat/apps/swat/source/class/swat/module/ldbbrowse/Fsm.js383
-rw-r--r--swat/apps/swat/source/class/swat/module/ldbbrowse/Gui.js632
-rw-r--r--swat/apps/swat/source/class/swat/module/ldbbrowse/LdbBrowse.js52
-rw-r--r--swat/apps/swat/source/class/swat/module/statistics/Fsm.js26
-rw-r--r--swat/apps/swat/source/class/swat/module/statistics/Gui.js4
-rw-r--r--swat/apps/swat/source/class/swat/module/statistics/Statistics.js3
11 files changed, 1145 insertions, 57 deletions
diff --git a/swat/apps/swat/source/class/swat/main/Main.js b/swat/apps/swat/source/class/swat/main/Main.js
index 85e2140215..dc3bbc031e 100644
--- a/swat/apps/swat/source/class/swat/main/Main.js
+++ b/swat/apps/swat/source/class/swat/main/Main.js
@@ -29,6 +29,10 @@ function()
new swat.module.Module("Statistics",
swat.module.statistics.Statistics);
+//#require(swat.module.ldbbrowse.LdbBrowse)
+new swat.module.Module("LDB Browser",
+ swat.module.ldbbrowse.LdbBrowse);
+
//#require(swat.module.documentation.Documentation)
//#require(api.Viewer)
new swat.module.Module("API Documentation",
@@ -53,10 +57,7 @@ qx.Proto.initialize = function()
var moduleList = swat.module.Module.getList();
for (moduleName in moduleList)
{
- // ... add the module's name to the module object, ...
- moduleList[moduleName].name = moduleName;
-
- // ... and call the module's buildInitialFsm() function
+ // ... call the module's buildInitialFsm() function
var module = moduleList[moduleName]["class"].getInstance();
module.buildInitialFsm(moduleList[moduleName]);
}
diff --git a/swat/apps/swat/source/class/swat/module/AbstractModule.js b/swat/apps/swat/source/class/swat/module/AbstractModule.js
index 2effa54b05..19bcc88a13 100644
--- a/swat/apps/swat/source/class/swat/module/AbstractModule.js
+++ b/swat/apps/swat/source/class/swat/module/AbstractModule.js
@@ -22,22 +22,12 @@ function()
* Build the initial finite state machine.
*
* In order to prevent long load times, as minimal as possible of an initial
- * FSM should be created. The FSM will receive a "visible" event when the
+ * FSM should be created. The FSM will receive an "appear" event when the
* module is first selected (and each subsequent time), and the FSM can use
* that event to build the complete FSM.
*
- * @param module {Object}
- * An object containing at least the following properties:
- * fsm -
- * The finite state machine for this module. It should be filled in
- * by this function.
- * canvas -
- * The canvas on which to create the gui for this module
- * name -
- * The name of this module
- * class -
- * The class for this module
- *
+ * @param module {swat.module.Module}
+ * The module descriptor for the module.
*/
qx.Proto.buildInitialFsm = function(module)
{
@@ -115,6 +105,20 @@ qx.Proto.buildInitialFsm = function(module)
// Save the finite state machine for this module
module.fsm = fsm;
+ // Save the module descriptor in the finite state machine
+ fsm.addObject("swat.module.module", module);
+
+ // Create an RPC object for use by this module
+ module.rpc = new qx.io.remote.Rpc();
+ module.rpc.setUrl("/services/");
+ module.rpc.setTimeout(10000);
+ module.rpc.setCrossDomain(false);
+ module.rpc.addEventListener("completed", fsm.eventListener, fsm);
+ module.rpc.addEventListener("failed", fsm.eventListener, fsm);
+ module.rpc.addEventListener("timeout", fsm.eventListener, fsm);
+ module.rpc.addEventListener("aborted", fsm.eventListener, fsm);
+ fsm.addObject("swat.module.rpc", module.rpc);
+
// Start the finite state machine
fsm.start();
};
diff --git a/swat/apps/swat/source/class/swat/module/AbstractModuleFsm.js b/swat/apps/swat/source/class/swat/module/AbstractModuleFsm.js
index 8f3b7caa80..57b8baaac9 100644
--- a/swat/apps/swat/source/class/swat/module/AbstractModuleFsm.js
+++ b/swat/apps/swat/source/class/swat/module/AbstractModuleFsm.js
@@ -35,8 +35,8 @@ qx.Proto.addAwaitRpcResultState = function(module)
* - disable any objects in group "swat.module.fsmUtils.disable_during_rpc"
*
* Actions upon exit:
- * - disable any objects in group "group_enable_during_rpc"
- * - enable any objects in group "group_disable_during_rpc"
+ * - disable any objects in group "swat.module.fsmUtils.enable_during_rpc"
+ * - enable any objects in group "swat.module.fsmUtils.disable_during_rpc"
*
* Transition on:
* "completed" (on RPC)
@@ -173,11 +173,11 @@ qx.Proto.addAwaitRpcResultState = function(module)
var request = fsm.getObject("swat.module.fsmUtils.request");
// Generate the result for a completed request
- request.result =
- {
- type : "complete",
- data : event.getData()
- };
+ request.setUserData("result",
+ {
+ type : "complete",
+ data : event.getData()
+ });
}
});
state.addTransition(trans);
@@ -200,18 +200,12 @@ qx.Proto.addAwaitRpcResultState = function(module)
var request = fsm.getObject("swat.module.fsmUtils.request");
// Generate the result for a completed request
- request.result =
- {
- type : "failed",
- data : event.getData()
- };
+ request.setUserData("result",
+ {
+ type : "failed",
+ data : event.getData()
+ });
}
});
state.addTransition(trans);
};
-
-
-/**
- * Singleton Instance Getter
- */
-qx.Class.getInstance = qx.util.Return.returnInstance;
diff --git a/swat/apps/swat/source/class/swat/module/Module.js b/swat/apps/swat/source/class/swat/module/Module.js
index e1f02caaba..e7180d2895 100644
--- a/swat/apps/swat/source/class/swat/module/Module.js
+++ b/swat/apps/swat/source/class/swat/module/Module.js
@@ -10,6 +10,33 @@
/**
* This class defines a module descriptor (the registration of a module) and
* maintains the list of modules that have been registered.
+ *
+ * A Module object contains the following public properties which may be
+ * accessed directly by name:
+ *
+ * fsm -
+ * The finite state machine for this module.
+ *
+ * canvas -
+ * The canvas on which to create the gui for this module
+ *
+ * name -
+ * The name of this module
+ *
+ * class -
+ * The class for this module
+ *
+ * @param moduleName {string}
+ * The name of the module being registered. This is the name that will
+ * appear in the Modules menu.
+ *
+ * @param class {class}
+ * The class which contains the module implementation. That class must
+ * extend swat.module.AbstractModule and implement a singleton interface
+ * that provides a public method called initialAppear() which takes this
+ * Module object as a parameter, and creates the finite state machine for
+ * the module (if applicable) and builds the graphical user interface for
+ * the module.
*/
qx.OO.defineClass("swat.module.Module", qx.core.Object,
function(moduleName, class)
@@ -21,6 +48,9 @@ function(moduleName, class)
this.fsm = null;
this.gui = null;
+ // Save the module name
+ this.name = moduleName;
+
// Save this class name
this.class = class;
diff --git a/swat/apps/swat/source/class/swat/module/documentation/Documentation.js b/swat/apps/swat/source/class/swat/module/documentation/Documentation.js
index eba62904a7..03191cacc2 100644
--- a/swat/apps/swat/source/class/swat/module/documentation/Documentation.js
+++ b/swat/apps/swat/source/class/swat/module/documentation/Documentation.js
@@ -25,7 +25,8 @@ function()
* appear. Creation of the module's GUI has been deferred until it was
* actually needed (now), so we need to create it.
*
- * @param module {Object} @see AbstractModule
+ * @param module {swat.module.Module}
+ * The module descriptor for the module.
*/
qx.Proto.initialAppear = function(module)
{
diff --git a/swat/apps/swat/source/class/swat/module/ldbbrowse/Fsm.js b/swat/apps/swat/source/class/swat/module/ldbbrowse/Fsm.js
new file mode 100644
index 0000000000..9362ef7687
--- /dev/null
+++ b/swat/apps/swat/source/class/swat/module/ldbbrowse/Fsm.js
@@ -0,0 +1,383 @@
+/*
+ * Copyright:
+ * (C) 2006 by Derrell Lipman
+ * All rights reserved
+ *
+ * License:
+ * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/
+ */
+
+/**
+ * Swat LDB Browser class finite state machine
+ */
+qx.OO.defineClass("swat.module.ldbbrowse.Fsm", swat.module.AbstractModuleFsm,
+function()
+{
+ swat.module.AbstractModuleFsm.call(this);
+});
+
+
+qx.Proto.buildFsm = function(module)
+{
+ var fsm = module.fsm;
+
+ /*
+ * State: Idle
+ *
+ * Actions upon entry
+ * - if returning from RPC, display the result
+ *
+ * Transition on:
+ * "execute" on find button
+ * "treeopenwhileempty" on tree
+ * "changeselection" on tree
+ */
+ var state = new qx.util.fsm.State(
+ "State_Idle",
+ {
+ "onentry" :
+ function(fsm, state)
+ {
+ // Did we just return from an RPC request?
+ if (fsm.getPreviousState() == "State_AwaitRpcResult")
+ {
+ // Yup. Display the result. We need to get the request object
+ var request = fsm.getObject("swat.module.fsmUtils.request");
+
+ // We don't need the request object to be saved any more
+ fsm.removeObject("swat.module.fsmUtils.request");
+
+ // Display the result
+ var gui = swat.module.ldbbrowse.Gui.getInstance();
+ gui.displayData(module, request);
+
+ // Dispose of the request
+ request.dispose();
+ request = null;
+ }
+ },
+
+ "events" :
+ {
+ // If the find button is activated, issue a find request
+ "execute" :
+ {
+ "find" :
+ "Transition_Idle_to_AwaitRpcResult_via_find"
+ },
+
+ // If a previously unexpanded tree node is expanded, issue a request
+ // to retrieve its contents.
+ "treeOpenWhileEmpty":
+ {
+ "tree" :
+ "Transition_Idle_to_AwaitRpcResult_via_tree_open"
+ },
+
+ // If the selection changes, issue a request to retrieve contents to
+ // populate the attribute/value table.
+ "changeSelection":
+ {
+ "tree:manager" :
+ "Transition_Idle_to_AwaitRpcResult_via_tree_selection_changed",
+
+ "dbName":
+ "Transition_Idle_to_AwaitRpcResult_via_db_changed"
+ }
+ }
+ });
+
+ // Replace the initial Idle state with this one
+ fsm.replaceState(state, true);
+
+ /*
+ * Transition: Idle to AwaitRpcResult
+ *
+ * Cause: "execute" on find button
+ *
+ * Action:
+ * Issue a search request
+ */
+ var trans = new qx.util.fsm.Transition(
+ "Transition_Idle_to_AwaitRpcResult_via_find",
+ {
+ "nextState" :
+ "State_AwaitRpcResult",
+
+ "ontransition" :
+ function(fsm, event)
+ {
+ // Obtain the RPC object
+ var rpc = fsm.getObject("swat.module.rpc");
+
+ // Get our module descriptor
+ var module = fsm.getObject("swat.module.module");
+
+ // Retrieve the database handle
+ var dbHandle = module.dbHandle;
+
+ // Retrieve the search expression
+ var searchExpr = fsm.getObject("searchExpr").getValue();
+
+ // Retrieve the base DN
+ var baseDN = fsm.getObject("baseDN").getValue();
+
+ // Retrieve the selected scope
+ var scope = fsm.getObject("scope").getSelected().getValue();
+
+ // We want all attributes
+ var attributes = [ "*" ];
+
+ rpc.setServiceName("samba.ldb");
+ var request = rpc.callAsyncListeners(true, // coalesce failure events
+ "search",
+ dbHandle,
+ searchExpr,
+ baseDN,
+ scope,
+ attributes);
+
+ // When we get the result, we'll need to know what type of request
+ // we made.
+ request.setUserData("requestType", "find");
+
+ // Save the request object
+ fsm.addObject("swat.module.fsmUtils.request", request);
+ }
+ });
+ state.addTransition(trans);
+
+ /*
+ * Transition: Idle to AwaitRpcResult
+ *
+ * Cause: "treeOpenWhileEmpty" on tree
+ *
+ * Action:
+ * Issue a search request
+ */
+ var trans = new qx.util.fsm.Transition(
+ "Transition_Idle_to_AwaitRpcResult_via_tree_open",
+ {
+ "nextState" :
+ "State_AwaitRpcResult",
+
+ "ontransition" :
+ function(fsm, event)
+ {
+ var parent = event.getData();
+ var hierarchy = parent.getHierarchy(new Array());
+
+ parent.debug("Requesting children...");
+
+ // 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)
+ {
+ // ... then we want the defaultNamingContext, ...
+ attributes = [ "defaultNamingContext" ];
+
+ // ... and we want only base scope
+ scope = "base";
+
+ // ... and an empty base DN
+ baseDN = "";
+ }
+ else
+ {
+ // otherwise, retrieve the DN,
+ attributes = [ "dn" ];
+
+ // ... and we want one level of scope
+ scope = "one";
+
+ // ... and base DN is the parent
+ baseDN = hierarchy.reverse().join(",");
+ }
+
+ // Build the search expression
+ var searchExpr = "(objectclass=*)";
+
+ // Obtain the RPC object
+ var rpc = fsm.getObject("swat.module.rpc");
+
+ // Get our module descriptor
+ var module = fsm.getObject("swat.module.module");
+
+ // Retrieve the database handle
+ var dbHandle = module.dbHandle;
+
+ rpc.setServiceName("samba.ldb");
+ var request = rpc.callAsyncListeners(true, // coalesce failure events
+ "search",
+ dbHandle,
+ searchExpr,
+ baseDN,
+ scope,
+ attributes);
+
+ // When we get the result, we'll need to know what type of request
+ // we made.
+ request.setUserData("requestType", "tree_open");
+
+ // We'll also need some of our parameters
+ request.setUserData("parent", parent);
+ request.setUserData("attributes", attributes);
+
+ // Save the request object
+ fsm.addObject("swat.module.fsmUtils.request", request);
+ }
+ });
+ state.addTransition(trans);
+
+ /*
+ * Transition: Idle to AwaitRpcResult
+ *
+ * Cause: "changeSelection" on tree
+ *
+ * Action:
+ * Issue a search request
+ */
+ var trans = new qx.util.fsm.Transition(
+ "Transition_Idle_to_AwaitRpcResult_via_tree_selection_changed",
+ {
+ "nextState" :
+ "State_AwaitRpcResult",
+
+ "predicate" :
+ function(fsm, event)
+ {
+ var element = event.getData()[0];
+ var hierarchy = element.getHierarchy(new Array());
+
+ // Strip off the root node
+ hierarchy.shift();
+
+ // Get the tree object
+ var tree = fsm.getObject("tree");
+
+ // If element is the root...
+ if (element == tree)
+ {
+ // ... then just clear out the attribute/value table.
+ var tableModel = fsm.getObject("tableModel:browse");
+ tableModel.setData([]);
+ return null; // don't search additional transitionis
+ }
+
+ return true;
+ },
+
+ "ontransition" :
+ function(fsm, event)
+ {
+ var element = event.getData()[0];
+ var hierarchy = element.getHierarchy(new Array());
+
+ // 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;
+
+ // We want all attributes
+ attributes = [ "*" ];
+
+ // We want the attributes only for the current element
+ scope = "base";
+
+ // Base DN is the current element
+ baseDN = hierarchy.reverse().join(",");
+
+ // Build the search expression
+ var searchExpr = "(objectclass=*)";
+
+ // Obtain the RPC object
+ var rpc = fsm.getObject("swat.module.rpc");
+
+ // Get our module descriptor
+ var module = fsm.getObject("swat.module.module");
+
+ // Retrieve the database handle
+ var dbHandle = module.dbHandle;
+
+ rpc.setServiceName("samba.ldb");
+ var request = rpc.callAsyncListeners(true, // coalesce failure events
+ "search",
+ dbHandle,
+ searchExpr,
+ baseDN,
+ scope,
+ attributes);
+
+ // When we get the result, we'll need to know what type of request
+ // we made.
+ request.setUserData("requestType", "tree_selection_changed");
+
+ // Save the request object
+ fsm.addObject("swat.module.fsmUtils.request", request);
+ }
+ });
+ state.addTransition(trans);
+
+ /*
+ * Transition: Idle to AwaitRpcResult
+ *
+ * Cause: "changeSelection" on dbName
+ *
+ * Action:
+ * Issue a connect request
+ */
+ var trans = new qx.util.fsm.Transition(
+ "Transition_Idle_to_AwaitRpcResult_via_db_changed",
+ {
+ "nextState" :
+ "State_AwaitRpcResult",
+
+ "ontransition" :
+ function(fsm, event)
+ {
+ // Obtain the RPC object
+ var rpc = fsm.getObject("swat.module.rpc");
+
+ // Obtain the name of the database to be connected to
+ var dbName = fsm.getObject("dbName").getValue();
+
+ rpc.setServiceName("samba.ldb");
+ var request = rpc.callAsyncListeners(true, // coalesce failure events
+ "connect",
+ dbName);
+
+ // When we get the result, we'll need to know what type of request
+ // we made.
+ request.setUserData("requestType", "database_name_changed");
+
+ // Save the request object
+ fsm.addObject("swat.module.fsmUtils.request", request);
+ }
+ });
+ state.addTransition(trans);
+
+ // Add the AwaitRpcResult state and all of its transitions
+ this.addAwaitRpcResultState(module);
+};
+
+
+/**
+ * Singleton Instance Getter
+ */
+qx.Class.getInstance = qx.util.Return.returnInstance;
diff --git a/swat/apps/swat/source/class/swat/module/ldbbrowse/Gui.js b/swat/apps/swat/source/class/swat/module/ldbbrowse/Gui.js
new file mode 100644
index 0000000000..9e86be25e9
--- /dev/null
+++ b/swat/apps/swat/source/class/swat/module/ldbbrowse/Gui.js
@@ -0,0 +1,632 @@
+/*
+ * Copyright:
+ * (C) 2006 by Derrell Lipman
+ * All rights reserved
+ *
+ * License:
+ * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/
+ */
+
+/**
+ * Swat LDB Browser class graphical user interface
+ */
+qx.OO.defineClass("swat.module.ldbbrowse.Gui", qx.core.Object,
+function()
+{
+ qx.core.Object.call(this);
+});
+
+
+/**
+ * Build the raw graphical user interface.
+ */
+qx.Proto.buildGui = function(module)
+{
+ var o;
+ var fsm = module.fsm;
+
+ // We need a horizontal box layout for the database name
+ var hlayout = new qx.ui.layout.HorizontalBoxLayout();
+ hlayout.set({
+ top: 20,
+ left: 20,
+ right: 20,
+ height: 30
+ });
+
+ // Create a label for the database name
+ o = new qx.ui.basic.Atom("Database:");
+ o.setWidth(100);
+ o.setHorizontalChildrenAlign("right");
+
+ // Add the label to the horizontal layout
+ hlayout.add(o);
+
+ // Create a combo box for for the database name
+ o = new qx.ui.form.ComboBox();
+ o.getField().setWidth("100%");
+ o.setEditable(false);
+
+ // Add our global database name (the only option, for now)
+ var item = new qx.ui.form.ListItem(module.dbFile);
+ o.add(item);
+
+ // We want to be notified if the selection changes
+ o.addEventListener("changeSelection", fsm.eventListener, fsm);
+
+ // Save the database name object so we can react to changes
+ fsm.addObject("dbName", o);
+
+ // Add the combo box to the horizontal layout
+ hlayout.add(o);
+
+ // Add the database name selection to the canvas
+ module.canvas.add(hlayout);
+
+ // Create and position the tabview
+ var tabView_ = new qx.ui.pageview.tabview.TabView;
+ tabView_.set({
+ top: 60,
+ left: 20,
+ right: 20,
+ bottom: 20
+ });
+
+ // Create each of the tabs
+ var tabView_Search =
+ new qx.ui.pageview.tabview.Button("Search");
+ var tabView_Browse =
+ new qx.ui.pageview.tabview.Button("Browse");
+
+ // Specify the initially-selected tab
+ tabView_Search.setChecked(true);
+
+ // Add each of the tabs to the tabview
+ tabView_.getBar().add(tabView_Search, tabView_Browse);
+
+ // Create the pages to display when each tab is selected
+ var tabViewPage_Search =
+ new qx.ui.pageview.tabview.Page(tabView_Search);
+ var tabViewPage_Browse =
+ new qx.ui.pageview.tabview.Page(tabView_Browse);
+
+ // Build the search page
+ this._buildPageSearch(module, tabViewPage_Search);
+
+ // Build the browse page
+ this._buildPageBrowse(module, tabViewPage_Browse);
+
+ // Add the pages to the tabview
+ tabView_.getPane().add(tabViewPage_Search, tabViewPage_Browse);
+
+ // Add the tabview to our canvas
+ module.canvas.add(tabView_);
+};
+
+
+/**
+ * Populate the graphical user interface with the specified data
+ *
+ * @param module {swat.module.Module}
+ * The module descriptor for the module.
+ *
+ * @result {Object}
+ * The result returned by SAMBA to our request. We display the data
+ * provided by this result.
+ */
+qx.Proto.displayData = function(module, request)
+{
+ var gui = module.gui;
+ var fsm = module.fsm;
+ var result = request.getUserData("result")
+ var requestType = request.getUserData("requestType");
+
+ // Did the request fail?
+ if (result.type == "failed")
+ {
+ // Yup. We're not going to do anything particularly elegant...
+ alert("Async(" + result.id + ") exception: " + result.data);
+ return;
+ }
+
+ // Dispatch to the appropriate handler, depending on the request type
+ switch(requestType)
+ {
+ case "find":
+ this._displayFindResults(module, request);
+ break;
+
+ case "tree_open":
+ this._displayTreeOpenResults(module, request);
+ break;
+
+ case "tree_selection_changed":
+ this._displayTreeSelectionChangedResults(module, request);
+ break;
+
+ case "database_name_changed":
+ this._clearAllFields(module, request);
+ break;
+
+ default:
+ throw new Error("Unexpected request type: " + requestType);
+ }
+
+ // Force flushing of pending DOM updates. This is actually a
+ // work-around for a bug. Without this, occasionally, updates to the
+ // gui aren't displayed until some 'action' takes place, e.g. key
+ // press or mouse movement.
+ qx.ui.core.Widget.flushGlobalQueues();
+};
+
+
+qx.Proto._setAppearances = function()
+{
+ // Modify the default appearance of a ComboBox for use in Search tab:
+ // use more of the available width.
+ //
+ // If we had multiple uses, we'd create a new appearance which didn't
+ // contain a width. That way, we'd be able to assign a specific width to
+ // each ComboBox instance. Since we don't have multiple of them, we can
+ // just modify this default appearance.
+ //
+ // See http://qooxdoo.org/documentation/user_manual/appearance for an
+ // explanation of what's going on here. The missing significant point in
+ // the discussion is that in the current qooxdoo appearance
+ // implementation, it's not possible to override a specific widget's
+ // appearance with explicit settings just for that widget (stupid!). I
+ // expect that to change in a future version.
+ var appMgr = qx.manager.object.AppearanceManager.getInstance();
+ var theme = appMgr.getAppearanceTheme();
+ var appearance = theme._appearances["combo-box"];
+ if (! appearance)
+ {
+ return;
+ }
+ var oldInitial = appearance.initial;
+ appearance.initial = function(vTheme)
+ {
+ var res = oldInitial ? oldInitial.apply(this, arguments) : {};
+ res.width = "80%";
+ return res;
+ }
+};
+
+
+qx.Proto._buildPageSearch = function(module, page)
+{
+ var fsm = module.fsm;
+
+ // We need a vertical box layout for the various input fields
+ var vlayout = new qx.ui.layout.VerticalBoxLayout();
+ vlayout.setWidth("100%");
+
+ // We need a horizontal box layout for the search combo box and its label
+ var hlayout = new qx.ui.layout.HorizontalBoxLayout();
+ hlayout.setWidth("100%");
+ hlayout.setHeight(25);
+
+ // Create a label for the list of required attributes
+ var label = new qx.ui.basic.Atom("Search Expression:");
+ label.setWidth(100);
+ label.setHorizontalChildrenAlign("right");
+
+ // Add the label to the horizontal layout
+ hlayout.add(label);
+
+ // Create a combo box for entry of the search expression
+ var search = new qx.ui.form.ComboBox();
+ search.getField().setWidth("100%");
+ search.setEditable(true);
+ fsm.addObject("searchExpr", search);
+
+ // Add the combo box to the horizontal layout
+ hlayout.add(search);
+
+ // Add the horizontal layout to the vertical layout
+ vlayout.add(hlayout);
+
+ // We need a horizontal box layout for the base combo box and its label
+ hlayout = new qx.ui.layout.HorizontalBoxLayout();
+ hlayout.setWidth("100%");
+ hlayout.setHeight(25);
+
+ // Create a label for the list of required attributes
+ var label = new qx.ui.basic.Atom("Base:");
+ label.setWidth(100);
+ label.setHorizontalChildrenAlign("right");
+
+ // Add the label to the horizontal layout
+ hlayout.add(label);
+
+ // Create a combo box for entry of the search expression
+ var base = new qx.ui.form.ComboBox();
+ base.getField().setWidth("100%");
+ base.setEditable(true);
+ fsm.addObject("baseDN", base);
+
+ // Add the combo box to the horizontal layout
+ hlayout.add(base);
+
+ // Add the horizontal layout to the vertical layout
+ vlayout.add(hlayout);
+
+ // We need a horizontal box layout for scope radio buttons
+ hlayout = new qx.ui.layout.HorizontalBoxLayout();
+ hlayout.setWidth("100%");
+ hlayout.setHeight(25);
+
+ // Create a label for the list of required attributes
+ var label = new qx.ui.basic.Atom("Scope:");
+ label.setWidth(100);
+ label.setHorizontalChildrenAlign("right");
+
+ // Add the label to the horizontal layout
+ hlayout.add(label);
+
+ // Create a radio button for each scope
+ var rbDefault = new qx.ui.form.RadioButton("Default", "default");
+ var rbBase = new qx.ui.form.RadioButton("Base", "base");
+ var rbOne = new qx.ui.form.RadioButton("One Level", "one");
+ var rbSubtree = new qx.ui.form.RadioButton("Subtree", "subtree");
+
+ // Use a default of "Default"
+ rbBase.setChecked(true);
+
+ // Add the radio buttons to the horizontal layout
+ hlayout.add(rbDefault, rbBase, rbOne, rbSubtree);
+
+ // Group the radio buttons so only one in the group may be selected
+ var scope = new qx.manager.selection.RadioManager("scope",
+ [
+ rbDefault,
+ rbBase,
+ rbOne,
+ rbSubtree
+ ]);
+ fsm.addObject("scope", scope);
+
+ // Right-justify the 'Find' button
+ var spacer = new qx.ui.basic.HorizontalSpacer;
+ hlayout.add(spacer);
+
+ // Create the 'Find' button
+ var find = new qx.ui.form.Button('Find');
+ find.setWidth(100);
+ find.addEventListener("execute", fsm.eventListener, fsm);
+
+ // We'll be receiving events on the find object, so save its friendly name
+ fsm.addObject("find", find, "swat.module.fsmUtils.disable_during_rpc");
+
+ hlayout.add(find);
+
+ // Add the Find button line to the vertical layout
+ vlayout.add(hlayout);
+
+ // Add the horizontal box layout to the page
+ page.add(vlayout);
+
+ // Create a simple table model
+ var tableModel = new qx.ui.table.SimpleTableModel();
+ tableModel.setColumns([ "Distinguished Name", "Attribute", "Value" ]);
+
+ tableModel.setColumnEditable(0, false);
+ tableModel.setColumnEditable(1, false);
+ tableModel.setColumnEditable(2, false);
+ fsm.addObject("tableModel:search", tableModel);
+
+ // Create a table
+ var table = new qx.ui.table.Table(tableModel);
+ table.set({
+ top: 80,
+ left: 0,
+ right: 0,
+ bottom: 10,
+ statusBarVisible: false,
+ columnVisibilityButtonVisible: false
+ });
+ table.setColumnWidth(0, 300);
+ table.setColumnWidth(1, 180);
+ table.setColumnWidth(2, 240);
+ table.setMetaColumnCounts([ 1, -1 ]);// h-scroll attribute and value together
+ fsm.addObject("table:search", table);
+
+ page.add(table);
+};
+
+qx.Proto._buildPageBrowse = function(module, page)
+{
+ var fsm = module.fsm;
+
+ // Create a vertical splitpane for tree (top) and table (bottom)
+ var splitpane = new qx.ui.splitpane.VerticalSplitPane("1*", "2*");
+ splitpane.setEdge(0);
+
+ // 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);
+ tree.set({
+ backgroundColor: 255,
+ border: qx.renderer.border.BorderPresets.getInstance().inset,
+ overflow: "auto",
+ height: null,
+ top: 10,
+ left: 0,
+ right: 0,
+ bottom: 10,
+ open: false,
+ alwaysShowPlusMinusSymbol: 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);
+
+ // 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);
+
+ // 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 tree to the page.
+ splitpane.addTop(tree);
+
+ // Create a simple table model
+ var tableModel = new qx.ui.table.SimpleTableModel();
+ tableModel.setColumns([ "Attribute", "Value" ]);
+
+ tableModel.setColumnEditable(0, false);
+ tableModel.setColumnEditable(1, false);
+ fsm.addObject("tableModel:browse", tableModel);
+
+ // Create a table
+ var table = new qx.ui.table.Table(tableModel);
+ table.set({
+ top: 10,
+ left: 0,
+ right: 0,
+ bottom: 10,
+ statusBarVisible: false,
+ columnVisibilityButtonVisible: false
+ });
+ table.setColumnWidth(0, 200);
+ table.setColumnWidth(1, 440);
+ table.setMetaColumnCounts([1, -1]);
+ fsm.addObject("table:browse", table);
+
+ // Add the table to the bottom portion of the splitpane
+ splitpane.addBottom(table);
+
+ // Add the first splitpane to the page
+ page.add(splitpane);
+};
+
+
+qx.Proto._displayFindResults = function(module, request)
+{
+ var rowData = [];
+ var fsm = module.fsm;
+
+ // Track the maximum length of the attribute values
+ var maxLen = 0;
+
+ // Obtain the result object
+ result = request.getUserData("result").data;
+
+ if (result && result["length"])
+ {
+ len = result["length"];
+ for (var i = 0; i < result["length"]; i++)
+ {
+ var o = result[i];
+ if (typeof(o) != "object")
+ {
+ alert("Found unexpected result, type " +
+ typeof(o) +
+ ", " +
+ o +
+ "\n");
+ continue;
+ }
+ for (var field in o)
+ {
+ // skip dn and distinguishedName fields;
+ // they're shown in each row anyway.
+ if (field == "dn" || field == "distinguishedName")
+ {
+ continue;
+ }
+
+ // If it's multi-valued (type is an array)...
+ if (typeof(o[field]) == "object")
+ {
+ // ... then add each value with same name
+ var a = o[field];
+ for (var i = 0; i < a.length; i++)
+ {
+ if (a[i].length > maxLen)
+ {
+ maxLen = a[i].length;
+ }
+ rowData.push( [
+ o["dn"],
+ field,
+ a[i]
+ ] );
+ }
+ }
+ else // single-valued
+ {
+ // ... add its name and value to the table
+ // dataset
+ if (o[field].length > maxLen)
+ {
+ maxLen = o[field].length;
+ }
+ rowData.push( [
+ o["dn"],
+ field,
+ o[field]
+ ] );
+ }
+ }
+
+ // Obtain the table and tableModel objects
+ var table = fsm.getObject("table:search");
+ var tableModel = fsm.getObject("tableModel:search");
+
+ // Adjust the width of the value column based on
+ // maxLen
+ table.setColumnWidth(2, maxLen * 7);
+
+ // Tell the table to use the new data
+ tableModel.setData(rowData);
+ }
+ }
+ else
+ {
+ alert("No rows returned.");
+ }
+};
+
+
+qx.Proto._displayTreeOpenResults = function(module, request)
+{
+ var t;
+ var trs;
+ var child;
+
+ // Obtain the result object
+ var result = request.getUserData("result").data;
+
+ // We also need some of the original parameters passed to the request
+ var parent = request.getUserData("parent");
+ var attributes = request.getUserData("attributes");
+
+ // Any children?
+ if (! result || result["length"] == 0)
+ {
+ // Nope. Allow parent's expand/contract button to be removed
+ parent.setAlwaysShowPlusMinusSymbol(false);
+ return;
+ }
+
+ for (var i = 0; i < result.length; i++)
+ {
+ var name;
+
+ child = result[i];
+
+ // Determine name for new tree row. If first level, use entire
+ // DN. Otherwise, strip off first additional component.
+ if (attributes == "defaultNamingContext")
+ {
+ name = child["defaultNamingContext"];
+ }
+ else
+ {
+ 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);
+ }
+};
+
+
+qx.Proto._displayTreeSelectionChangedResults = function(module, request)
+{
+ var fsm = module.fsm;
+
+ // Obtain the result object
+ var result = request.getUserData("result").data;
+
+ // If we received an empty list, ...
+ if (result == null)
+ {
+ // ... then just clear the attribute/value table.
+ tableModel.setData([ ]);
+ return;
+ }
+
+ // Start with an empty table dataset
+ var rowData = [ ];
+
+ // The result contains a single object: attributes
+ var attributes = result[0];
+
+ // Track the maximum length of the attribute values
+ var maxLen = 0;
+
+ // For each attribute we received...
+ for (var attr in attributes)
+ {
+ // If it's multi-valued (type is an array)...
+ if (typeof(attributes[attr]) == "object")
+ {
+ // ... then add each value with same name
+ var a = attributes[attr];
+ for (var i = 0; i < a.length; i++)
+ {
+ if (a[i].length > maxLen)
+ {
+ maxLen = a[i].length;
+ }
+ rowData.push([ attr, a[i] ]);
+ }
+ }
+ else // single-valued
+ {
+ // ... add its name and value to the table dataset
+ if (attributes[attr].length > maxLen)
+ {
+ maxLen = attributes[attr].length;
+ }
+ rowData.push([ attr, attributes[attr] ]);
+ }
+ }
+
+ // Obtain the table and tableModel objects
+ var table = fsm.getObject("table:browse");
+ var tableModel = fsm.getObject("tableModel:browse");
+
+ // Adjust the width of the value column based on maxLen
+ table.setColumnWidth(1, maxLen * 7);
+
+ // Add the dataset to the table
+ tableModel.setData(rowData);
+};
+
+
+qx.Proto._clearAllFields = function(module, request)
+{
+ // Obtain the result object
+ var result = request.getUserData("result").data;
+
+ // Retrieve the database handle
+ module.dbHandle = result;
+
+ // In the future, when we support more than one database, we'll want to
+ // clear all fields here. For now, there's no need.
+};
+
+
+
+/**
+ * Singleton Instance Getter
+ */
+qx.Class.getInstance = qx.util.Return.returnInstance;
diff --git a/swat/apps/swat/source/class/swat/module/ldbbrowse/LdbBrowse.js b/swat/apps/swat/source/class/swat/module/ldbbrowse/LdbBrowse.js
new file mode 100644
index 0000000000..45a4c48930
--- /dev/null
+++ b/swat/apps/swat/source/class/swat/module/ldbbrowse/LdbBrowse.js
@@ -0,0 +1,52 @@
+/*
+ * Copyright:
+ * (C) 2006 by Derrell Lipman
+ * All rights reserved
+ *
+ * License:
+ * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/
+ */
+
+/**
+ * Swat LDB Browser class
+ */
+qx.OO.defineClass("swat.module.ldbbrowse.LdbBrowse",
+ swat.module.AbstractModule,
+function()
+{
+ swat.module.AbstractModule.call(this);
+});
+
+
+/**
+ * Create the module's finite state machine and graphical user interface.
+ *
+ * This function is called the first time a module is actually selected to
+ * appear. Creation of the module's actual FSM and GUI have been deferred
+ * until they were actually needed (now) so we need to create them.
+ *
+ * @param module {swat.module.Module}
+ * The module descriptor for the module.
+ */
+qx.Proto.initialAppear = function(module)
+{
+ // Initial database to open
+ module.dbFile = "sam.ldb";
+
+ // Replace the existing (temporary) finite state machine with the real one
+ swat.module.ldbbrowse.Fsm.getInstance().buildFsm(module);
+
+ // Create the real gui
+ swat.module.ldbbrowse.Gui.getInstance().buildGui(module);
+
+ // Force the global database to be opened
+ var dbName = module.fsm.getObject("dbName");
+ dbName.setSelected(dbName.getList().getFirstChild());
+ dbName.dispatchEvent(new qx.event.type.Event("changeSelection"), true);
+};
+
+
+/**
+ * Singleton Instance Getter
+ */
+qx.Class.getInstance = qx.util.Return.returnInstance;
diff --git a/swat/apps/swat/source/class/swat/module/statistics/Fsm.js b/swat/apps/swat/source/class/swat/module/statistics/Fsm.js
index 486463d648..771044172e 100644
--- a/swat/apps/swat/source/class/swat/module/statistics/Fsm.js
+++ b/swat/apps/swat/source/class/swat/module/statistics/Fsm.js
@@ -74,10 +74,10 @@ qx.Proto.buildFsm = function(module)
// Display the result
var gui = swat.module.statistics.Gui.getInstance();
- gui.displayData(module, request.result);
+ gui.displayData(module, request.getUserData("result"));
- // Dispose of the request (and result)
- request.result = null;
+ // Dispose of the request
+ request.dispose();
request = null;
// Restart the timer.
@@ -143,13 +143,12 @@ qx.Proto.buildFsm = function(module)
{
var rpc = fsm.getObject("swat.module.rpc");
- rpc.setUrl("/services/");
rpc.setServiceName("samba.management");
-
- var request =
- rpc.callAsyncListeners(true, // coalesce failure events
- "get_statistics",
- true, true);
+ var request = rpc.callAsyncListeners(true, // coalesce failure events
+ "get_statistics",
+ true,
+ true);
+ // Make the request object available to the AwaitRpcResult state
fsm.addObject("swat.module.fsmUtils.request", request);
}
});
@@ -201,15 +200,6 @@ qx.Proto.buildFsm = function(module)
// Add the AwaitRpcResult state and all of its transitions
this.addAwaitRpcResultState(module);
-
- // Allocate an RPC object
- o = new qx.io.remote.Rpc();
- o.setTimeout(10000);
- o.addEventListener("completed", fsm.eventListener, fsm);
- o.addEventListener("failed", fsm.eventListener, fsm);
- o.addEventListener("timeout", fsm.eventListener, fsm);
- o.addEventListener("aborted", fsm.eventListener, fsm);
- fsm.addObject("swat.module.rpc", o);
};
diff --git a/swat/apps/swat/source/class/swat/module/statistics/Gui.js b/swat/apps/swat/source/class/swat/module/statistics/Gui.js
index 050c488c5c..777caa7328 100644
--- a/swat/apps/swat/source/class/swat/module/statistics/Gui.js
+++ b/swat/apps/swat/source/class/swat/module/statistics/Gui.js
@@ -303,8 +303,8 @@ qx.Proto.buildGui = function(module)
/**
* Populate the graphical user interface with the specified data
*
- * @param module {Object}
- * The descriptor containing our module-specific information
+ * @param module {swat.module.Module}
+ * The module descriptor for the module.
*
* @result {Object}
* The result returned by SAMBA to our request for statistics. We display
diff --git a/swat/apps/swat/source/class/swat/module/statistics/Statistics.js b/swat/apps/swat/source/class/swat/module/statistics/Statistics.js
index 00adf2f866..1618ab73c5 100644
--- a/swat/apps/swat/source/class/swat/module/statistics/Statistics.js
+++ b/swat/apps/swat/source/class/swat/module/statistics/Statistics.js
@@ -25,7 +25,8 @@ function()
* appear. Creation of the module's actual FSM and GUI have been deferred
* until they were actually needed (now) so we need to create them.
*
- * @param module {Object} @see AbstractModule
+ * @param module {swat.module.Module}
+ * The module descriptor for the module.
*/
qx.Proto.initialAppear = function(module)
{