Split LauncherApplet in two applets and fix various bugs
authorCharles du Jeu <charles.dujeu@gmail.com>
Fri, 22 May 2009 18:11:49 +0000 (18:11 +0000)
committerCharles du Jeu <charles.dujeu@gmail.com>
Fri, 22 May 2009 18:11:49 +0000 (18:11 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@2434 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/LauncherPerspective.js
server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/BatchView.js [new file with mode: 0644]
server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/FlowsSelectorView.js [new file with mode: 0644]

index 8fb95ab80d1c9f4acaef4a03931d2a247903c7c7..8138bd0d88c56b019b9f75ed9f1410f44be55e2a 100644 (file)
@@ -17,39 +17,50 @@ qx.Class.define("org.argeo.slc.web.LauncherPerspective",
   },\r
     \r
   members : {\r
-       \r
-       _rightPane : null,\r
-               \r
+                       \r
        initViewPanes : function(viewsManager){\r
 \r
-      this._splitPane = new qx.ui.splitpane.Pane("horizontal");\r
-         var topLeft = new org.argeo.ria.components.ViewPane("form", "Execution Launcher", {\r
-               orientation : "horizontal",\r
-               min : 36\r
-         });\r
-         topLeft.set({width:290});\r
-         viewsManager.registerViewPane(topLeft);\r
-           \r
-         this._splitPane.add(topLeft, 0);\r
-         var rightPane = new org.argeo.ria.components.ViewPane("main", "Executions Log");        \r
-         viewsManager.registerViewPane(rightPane);\r
-         this._splitPane.add(rightPane, 1);\r
-      \r
+      this._splitPane = new qx.ui.splitpane.Pane("horizontal");      \r
+      this._secondSplit = new qx.ui.splitpane.Pane("vertical");\r
+      this._secondSplit.setDecorator(null);\r
+            \r
+         var selectorPane = new org.argeo.ria.components.ViewPane("selector", "Available Scripts");\r
+         selectorPane.set({width:290});\r
+         viewsManager.registerViewPane(selectorPane);\r
+         \r
+         var batchPane = new org.argeo.ria.components.ViewPane("batch", "Batch");\r
+         batchPane.set({height:300});\r
+         viewsManager.registerViewPane(batchPane);\r
+         \r
+         var logPane = new org.argeo.ria.components.ViewPane("main", "Executions Log");\r
+         viewsManager.registerViewPane(logPane);         \r
+         \r
+         this._secondSplit.add(batchPane, 0);    \r
+         this._secondSplit.add(logPane, 1);      \r
+         \r
+         this._splitPane.add(selectorPane, 0);   \r
+         this._splitPane.add(this._secondSplit, 1);\r
+\r
+         \r
       viewsManager.getViewPanesContainer().add(this._splitPane, {flex:1});\r
                \r
        },\r
        \r
        initViews : function(viewsManager){\r
-         var formApplet = viewsManager.initIViewClass(org.argeo.slc.ria.NewLauncherApplet, "form");\r
+         var formApplet = viewsManager.initIViewClass(org.argeo.slc.ria.FlowsSelectorView, "selector");\r
          formApplet.load();\r
          \r
+         var batchApplet = viewsManager.initIViewClass(org.argeo.slc.ria.BatchView, "batch");\r
+         batchApplet.load();\r
+         \r
          var logger = viewsManager.initIViewClass(org.argeo.slc.ria.SlcExecLoggerApplet, "main");\r
          logger.load();\r
        },\r
        \r
        remove : function(viewsManager){\r
                viewsManager.getViewPaneById("main").empty();\r
-               viewsManager.getViewPaneById("form").empty();\r
+               viewsManager.getViewPaneById("batch").empty();\r
+               viewsManager.getViewPaneById("selector").empty();\r
                viewsManager.getViewPanesContainer().remove(this._splitPane);           \r
        }       \r
        \r
diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/BatchView.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/BatchView.js
new file mode 100644 (file)
index 0000000..8769751
--- /dev/null
@@ -0,0 +1,391 @@
+/**\r
+ * Applet for the batch manager\r
+ */\r
+qx.Class.define("org.argeo.slc.ria.BatchView",\r
+{\r
+       extend : qx.ui.container.Composite,\r
+       implement : [org.argeo.ria.components.IView], \r
+\r
+       properties : \r
+       {\r
+               /**\r
+                * The commands definition Map that will be automatically added and wired to the menubar and toolbar.\r
+                * See {@link org.argeo.ria.event.CommandsManager#definitions} for the keys to use for defining commands.\r
+                */\r
+               commands : {\r
+                       init : {\r
+                               "submitform" : {\r
+                                       label : "Execute Batch",\r
+                                       icon : "resource/slc/media-playback-start.png",\r
+                                       shortcut : null,\r
+                                       enabled : false,\r
+                                       menu : "Launcher",\r
+                                       toolbar : "batch",\r
+                                       callback : function(e) {\r
+                                               if (this.getBatchAgentId()) {\r
+                                                       this.executeBatchOnAgent(this.getBatchAgentId());\r
+                                               }\r
+                                       },\r
+                                       command : null\r
+                               },\r
+                               "toggleopenonadd" : {\r
+                                       label : "Auto edit on Add",\r
+                                       icon : "resource/slc/document-open.png",\r
+                                       shortcut : null,\r
+                                       enabled : true,\r
+                                       toggle : true,\r
+                                       toggleInitialState : true,\r
+                                       menu : "Launcher",\r
+                                       toolbar : "launcher",\r
+                                       callback : function(event) {\r
+                                               var state = event.getTarget().getUserData("slc.command.toggleState");\r
+                                               this.setAutoOpen(state);\r
+                                       },\r
+                                       command : null\r
+                               },\r
+                               "editexecutionspecs" : {\r
+                                       label : "Edit Execution Specs",\r
+                                       icon : "resource/slc/document-open.png",\r
+                                       shortcut : null,\r
+                                       enabled : false,\r
+                                       menu : "Launcher",\r
+                                       toolbar : "batch",\r
+                                       callback : function(e) {\r
+                                               var sel = this.list.getSortedSelection();\r
+                                               var spec = sel[0].getUserData("batchEntrySpec");\r
+                                               if (spec.hasEditableValues()) {\r
+                                                       var specEditor = new org.argeo.slc.ria.execution.SpecEditor(spec);\r
+                                                       specEditor.attachAndShow();\r
+                                               }\r
+                                       },\r
+                                       selectionChange : function(viewId, selection) {\r
+                                               if (viewId != "form:list")\r
+                                                       return;\r
+                                               this.setEnabled(false);\r
+                                               if ((selection && selection.length == 1)) {\r
+                                                       var selectedItemSpec = selection[0].getUserData("batchEntrySpec");\r
+                                                       if (selectedItemSpec.hasEditableValues()) {\r
+                                                               this.setEnabled(true);\r
+                                                       }\r
+                                               }\r
+                                       },\r
+                                       command : null\r
+                               },\r
+                               "removefrombatch" : {\r
+                                       label : "Remove from batch",\r
+                                       icon : "resource/slc/edit-delete.png",\r
+                                       shortcut : null,\r
+                                       enabled : false,\r
+                                       menu : "Launcher",\r
+                                       toolbar : "batch",\r
+                                       callback : function(e) {\r
+                                               var sel = this.list.getSortedSelection();\r
+                                               var modal = new org.argeo.ria.components.Modal("Confirm", null);\r
+                                               modal.addConfirm("Are you sure you want to remove<br> the selected test"\r
+                                                                               + (sel.length > 1 ? "s" : "")\r
+                                                                               + " from the Batch?");\r
+                                               modal.addListener("ok", function() {\r
+                                                                       for (var i = 0; i < sel.length; i++) {\r
+                                                                               this.list.remove(sel[i]);\r
+                                                                       }\r
+                                                                       if (!this.list.hasChildren()) {\r
+                                                                               this.setBatchAgentId(null);\r
+                                                                       }\r
+                                                               }, this);\r
+                                               modal.attachAndShow();\r
+                                       },\r
+                                       selectionChange : function(viewId, selection) {\r
+                                               if (viewId != "form:list")\r
+                                                       return;\r
+                                               this.setEnabled(false);\r
+                                               if ((selection && selection.length > 0))\r
+                                                       this.setEnabled(true);\r
+                                       },\r
+                                       command : null\r
+                               }                               \r
+                       }\r
+               },\r
+               view : {\r
+                       init : null\r
+               },              \r
+               viewSelection : {\r
+                       nullable:false, \r
+                       check:"org.argeo.ria.components.ViewSelection"\r
+               },\r
+               instanceId : {init:""},\r
+               instanceLabel : {init:""},\r
+               /**\r
+                * A boolean registering whether the SpecEditor must autoOpen or not\r
+                * when a spec is added to the Batch.\r
+                */\r
+               autoOpen : {\r
+                       init : true,\r
+                       check : "Boolean"\r
+               },\r
+               batchAgentId : {\r
+                       init : null,\r
+                       nullable : true,\r
+                       check : "String",\r
+                       event : "changeBatchAgentId"\r
+               }               \r
+       },\r
+         \r
+       construct : function(){\r
+               this.base(arguments);\r
+               this.setLayout(new qx.ui.layout.Dock());        \r
+       },\r
+  \r
+       members : {\r
+               /**\r
+                * The implementation should contain the GUI initialisation.\r
+                * This is the role of the manager to actually add the graphical component to the pane, \r
+                * so it's not necessary to do it here. \r
+                * @param viewPane {org.argeo.ria.components.ViewPane} The pane manager\r
+                * @param data {Mixed} Any object or data passed by the initiator of the view\r
+                * @return {Boolean}\r
+                */\r
+               init : function(viewPane, data){\r
+                       this.setView(viewPane);                 \r
+                       this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId()));                        \r
+                       this._emptyAgentString = "Empty Batch (Drop scripts here)";\r
+                       this._crtAgentString = "Batch Execution on Agent ";\r
+                       \r
+               },\r
+               /**\r
+                * The implementation should contain the real data loading (i.o. query...)\r
+                * @return {Boolean}\r
+                */\r
+               load : function(){\r
+                       this._createLayout();\r
+                       this.getView().setViewTitle(this._emptyAgentString);\r
+                       //this.getView().setViewTitle("");\r
+               },\r
+               \r
+               /**\r
+                * Creates the main applet layout.\r
+                */\r
+               _createLayout : function() {\r
+                       this.listPane = new qx.ui.container.Composite(new qx.ui.layout.Dock());\r
+                       this.addListener("changeBatchAgentId", function(event) {\r
+                               var value = event.getData();\r
+                               if (value == null) {\r
+                                       this.getView().setViewTitle(this._emptyAgentString);\r
+                               } else {\r
+                                       var selectorView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("selector").getContent();\r
+                                       if(selectorView){\r
+                                               var agentsMap = selectorView.getAgentsMap();\r
+                                               this.getView().setViewTitle(this._crtAgentString + "'" + agentsMap[value] + "'");\r
+                                       }\r
+                               }\r
+                       }, this);\r
+                       \r
+                       var indicator = new qx.ui.core.Widget();\r
+                       indicator.setDecorator(new qx.ui.decoration.Single().set({\r
+                                               top : [1, "solid", "#33508D"]\r
+                                       }));\r
+                       indicator.setHeight(0);\r
+                       indicator.setOpacity(0.5);\r
+                       indicator.setZIndex(100);\r
+                       indicator.setLayoutProperties({\r
+                                               left : -1000,\r
+                                               top : -1000\r
+                                       });\r
+                       org.argeo.ria.Application.INSTANCE.getRoot().add(indicator);\r
+\r
+                       this.list = new qx.ui.form.List();\r
+                       this.list.setDecorator(null);\r
+                       this.list.setSelectionMode("multi");\r
+                       this.list.setDroppable(true);\r
+                       this.list.setDraggable(true);\r
+                       this.list.setContextMenu(org.argeo.ria.event.CommandsManager\r
+                                       .getInstance().createMenuFromIds(["editexecutionspecs",\r
+                                                       "removefrombatch"]));\r
+\r
+                       this.list.addListener("dragstart", function(e) {\r
+                                               e.addType(["items"]);\r
+                                               e.addAction(["move"]);\r
+                                       }, this);\r
+                       this.list.addListener("dragend", function(e) {\r
+                                               indicator.setDomPosition(-1000, -1000);\r
+                                       });\r
+                       this.list.addListener("dragover", function(e) {\r
+                                               var orig = e.getOriginalTarget();\r
+                                               var origCoords = orig.getContainerLocation();\r
+                                               indicator.setWidth(orig.getBounds().width);\r
+                                               indicator.setDomPosition(origCoords.left,\r
+                                                               origCoords.bottom);\r
+                                       });\r
+                       this.list.addListener("drag", function(e) {\r
+                                               var orig = e.getOriginalTarget();\r
+                                               var origCoords = orig.getContainerLocation();\r
+                                               indicator.setWidth(orig.getBounds().width);\r
+                                               indicator.setDomPosition(origCoords.left,\r
+                                                               origCoords.bottom);\r
+                                       });\r
+\r
+                       this.list.addListener("drop", function(e) {\r
+                                               var target = e.getRelatedTarget();\r
+                                               var afterItem = e.getOriginalTarget();\r
+                                               indicator.setDomPosition(-1000, -1000);\r
+                                               if (afterItem.classname != "qx.ui.form.ListItem")\r
+                                                       afterItem = null;\r
+                                               if (!target) {\r
+                                                       target = this.list.getSortedSelection()[0];\r
+                                                       this.addFlowToBatch(target, afterItem);\r
+                                               } else {\r
+                                                       org.argeo.ria.event.CommandsManager.getInstance().executeCommand("addtobatch");\r
+                                               }\r
+                                       }, this);\r
+                       this.listPane.add(this.list, {\r
+                                               edge : "center"\r
+                                       });\r
+\r
+                       this.list.addListener("changeSelection", function(e) {\r
+                                               var viewSelection = this.getViewSelection();\r
+                                               viewSelection.setViewId("form:list");\r
+                                               viewSelection.clear();\r
+                                               var listSel = this.list.getSortedSelection();\r
+                                               for (var i = 0; i < listSel.length; i++) {\r
+                                                       viewSelection.addNode(listSel[i]);\r
+                                               }\r
+                                       }, this);\r
+\r
+                       listChangeListener = function() {\r
+                               var command = org.argeo.ria.event.CommandsManager.getInstance()\r
+                                               .getCommandById("submitform");\r
+                               command.setEnabled(this.list.hasChildren());\r
+                       };\r
+                       this.list.addListener("addItem", listChangeListener, this);\r
+                       this.list.addListener("removeItem", listChangeListener, this);\r
+\r
+                       \r
+                       this.add(this.listPane);\r
+               },              \r
+               \r
+               \r
+               /**\r
+                * Adds a given ExecutionFlow to the batch\r
+                * \r
+                * @param target\r
+                *            {mixed} The dropped target, can be a TreeFile (add) or a\r
+                *            ListItem (reorder).\r
+                * @param after\r
+                *            {qx.ui.form.ListItem} Optional list item : if set, the\r
+                *            flow will be added as a new list item positionned after\r
+                *            this one.\r
+                * @param skipAutoOpen\r
+                *            {boolean} Whether the formular should open or not.\r
+                */\r
+               addFlowToBatch : function(target, after, skipAutoOpen) {\r
+                       if (target && target.classname == "qx.ui.form.ListItem") {\r
+                               if (!after)\r
+                                       return;\r
+                               if (after == "first")\r
+                                       this.list.addAt(target, 0);\r
+                               else\r
+                                       this.list.addAfter(target, after);\r
+                               return;\r
+                       }\r
+\r
+                       // Folder case\r
+                       if (qx.Class.isSubClassOf(qx.Class.getByName(target.classname),\r
+                                       qx.ui.tree.TreeFolder)) {\r
+                               var allChildren = target.getItems(true);\r
+                               for (var i = 0; i < allChildren.length; i++) {\r
+                                       if (allChildren[i].getUserData("executionFlow")) {\r
+                                               try{\r
+                                                       this.addFlowToBatch(allChildren[i], null, true);\r
+                                               }catch(e){\r
+                                                       return;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               return;\r
+                       }\r
+\r
+                       // Check agent Uuid against current batch agent Id.\r
+                       var agentUuid = target.getUserData("agentUuid");\r
+                       if (!this.getBatchAgentId()) {\r
+                               this.setBatchAgentId(agentUuid);\r
+                       } else if (this.getBatchAgentId() != agentUuid) {\r
+                               this.error("Batch can contain tests only of the same agent!");                          \r
+                               throw new Error("Batch can contain tests only of the same agent!");\r
+                       }\r
+\r
+                       var executionModule = target.getUserData("executionModule");\r
+                       var executionFlow = target.getUserData("executionFlow");\r
+                       var batchEntry = new org.argeo.slc.ria.execution.BatchEntrySpec(\r
+                                       executionModule, executionFlow);\r
+                       var label = batchEntry.getLabel();\r
+                       var icon = target.getIcon() || "resource/slc/office-document.png";\r
+                       var item = new qx.ui.form.ListItem(label, icon);\r
+                       item.addListener("dblclick", function(e) {\r
+                                               this.getCommands()["editexecutionspecs"].command\r
+                                                               .execute();\r
+                                       }, this);\r
+                       item.setUserData("batchEntrySpec", batchEntry);\r
+                       item.setPaddingTop(1);\r
+                       item.setPaddingBottom(2);\r
+                       if (after) {\r
+                               if (after == "first")\r
+                                       this.list.addAt(item, 0);\r
+                               else\r
+                                       this.list.addAfter(item, after);\r
+                       } else {\r
+                               this.list.add(item);\r
+                       }\r
+                       this.list.select(item);\r
+                       if (this.getAutoOpen() && !skipAutoOpen) {\r
+                               this.getCommands()["editexecutionspecs"].command.execute();\r
+                       }\r
+               },\r
+\r
+               /**\r
+                * Called at execution\r
+                * \r
+                * @param agentUuid\r
+                *            {String} The id of the target agent\r
+                */\r
+               executeBatchOnAgent : function(agentUuid) {\r
+                       var selection = this.list.getChildren();\r
+                       if (!selection.length)\r
+                               return;\r
+                       var slcExecMessage = new org.argeo.slc.ria.execution.Message();\r
+                       for (var i = 0; i < selection.length; i++) {\r
+                               var batchEntrySpec = selection[i].getUserData("batchEntrySpec");\r
+                               slcExecMessage.addBatchEntrySpec(batchEntrySpec);\r
+                       }\r
+                       var req = org.argeo.slc.ria.SlcApi.getNewSlcExecutionService(\r
+                                       agentUuid, slcExecMessage.toXml());\r
+                       req.send();\r
+                       // Force logs refresh right now!\r
+                       qx.event.Timer.once(function() {\r
+                                               var command = org.argeo.ria.event.CommandsManager\r
+                                                               .getInstance().getCommandById("reloadlogs");\r
+                                               if (command) {\r
+                                                       command.execute();\r
+                                               }\r
+                                       }, this, 2000);\r
+               },\r
+               \r
+               clearBatchForAgentId : function(agentId){\r
+                       if(this.getBatchAgentId() == agentId){\r
+                               this.list.removeAll();                          \r
+                               this.setBatchAgentId(null);\r
+                       }\r
+               },\r
+               \r
+               /**\r
+                * Whether this component is already contained in a scroller (return false) or not (return true).\r
+                * @return {Boolean}\r
+                */\r
+               addScroll : function(){return false;},\r
+               /**\r
+                * Called at destruction time\r
+                * Perform all the clean operations (stopping polling queries, etc.) \r
+                */\r
+               close : function(){return true;}\r
+       }\r
+  \r
+\r
+});
\ No newline at end of file
diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/FlowsSelectorView.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/FlowsSelectorView.js
new file mode 100644 (file)
index 0000000..088f8f6
--- /dev/null
@@ -0,0 +1,484 @@
+/**\r
+ * The selector view\r
+ * \r
+ */\r
+qx.Class.define("org.argeo.slc.ria.FlowsSelectorView", {\r
+       extend : qx.ui.container.Composite,\r
+       implement : [org.argeo.ria.components.IView],\r
+\r
+       construct : function() {\r
+               this.base(arguments);\r
+               this.setLayout(new qx.ui.layout.Dock());\r
+       },\r
+\r
+       properties : {\r
+               /**\r
+                * The viewPane inside which this applet is added.\r
+                */\r
+               view : {\r
+                       init : null\r
+               },\r
+               viewSelection : {\r
+                       nullable : false,\r
+                       check : "org.argeo.ria.components.ViewSelection"\r
+               },\r
+               instanceId : {\r
+                       init : ""\r
+               },\r
+               instanceLabel : {\r
+                       init : ""\r
+               },\r
+               /**\r
+                * Commands definition, see\r
+                * {@link org.argeo.ria.event.CommandsManager#definitions}\r
+                */\r
+               commands : {\r
+                       init : {\r
+                               "addtobatch" : {\r
+                                       label : "Add to batch",\r
+                                       icon : "resource/slc/list-add.png",\r
+                                       shortcut : null,\r
+                                       enabled : true,\r
+                                       menu : null,\r
+                                       toolbar : null,\r
+                                       callback : function(e) {\r
+                                               if (this.tree.isSelectionEmpty()) {\r
+                                                       return;\r
+                                               }\r
+                                               var batchView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("batch").getContent();\r
+                                               if(!batchView) return;\r
+                                               selection = this.tree.getSelection();\r
+                                               if (selection.length > 1) {\r
+                                                       for (var i = 0; i < selection.length; i++) {\r
+                                                               try{\r
+                                                                       batchView.addFlowToBatch(selection[i], null, true);\r
+                                                               }catch(e){\r
+                                                                       return;\r
+                                                               }\r
+                                                       }\r
+                                                       return;\r
+                                               } else {\r
+                                                       try{\r
+                                                               batchView.addFlowToBatch(selection[0], null);\r
+                                                       }catch(e){\r
+                                                               return;\r
+                                                       }\r
+                                               }\r
+                                       },\r
+                                       selectionChange : function(viewId, selection) {\r
+                                               if (viewId != "form:tree")\r
+                                                       return;\r
+                                               if (!selection || selection.length != 1)\r
+                                                       return;\r
+                                               var item = selection[0];\r
+                                               this.setEnabled(false);\r
+                                               switch (item.classname) {\r
+                                                       case "qx.ui.tree.TreeFile" :\r
+                                                               this.setEnabled(true);\r
+                                                               break;\r
+                                                       case "qx.ui.tree.TreeFolder" :\r
+                                                               if (item.getTree().getRoot() == item)\r
+                                                                       break;\r
+                                                               this.setEnabled(true);\r
+                                                               break;\r
+                                                       case "org.argeo.ria.components.DynamicTreeFolder" :\r
+                                                               if (item.getTree().getRoot() == item)\r
+                                                                       break;  \r
+                                                               if (item.getState() == "loaded")\r
+                                                                       this.setEnabled(true);\r
+                                                               break;\r
+                                               }\r
+                                       },\r
+                                       command : null\r
+                               },\r
+                               "reloadtree" : {\r
+                                       label : "Reload",\r
+                                       icon : "resource/slc/view-refresh.png",\r
+                                       shortcut : "Control+m",\r
+                                       enabled : false,\r
+                                       menu : "Launcher",\r
+                                       toolbar : "launcher",\r
+                                       callback : function(e) {\r
+                                               if (this.tree.isSelectionEmpty()) {     return; }                                               \r
+                                               var selected = this.tree.getSelection()[0];\r
+                                               if (selected.classname == "org.argeo.ria.components.DynamicTreeFolder") {\r
+                                                       if (selected.getUserData("moduleData")) {\r
+                                                               // It's a "module" node, first trigger the\r
+                                                               // reloadBundle.service\r
+                                                               selected.setUserData("dataModel", {});\r
+                                                               selected.setEnabled(false);\r
+                                                               selected.setOpen(false);\r
+                                                               var moduleData = selected\r
+                                                                               .getUserData("moduleData");\r
+                                                               var bundleService = org.argeo.slc.ria.SlcApi\r
+                                                                               .getReloadBundleService(\r
+                                                                                               moduleData.name,\r
+                                                                                               moduleData.version);\r
+                                                               bundleService.addListener("completed",\r
+                                                                               function(response) {\r
+                                                                                       selected.setEnabled(true);\r
+                                                                                       selected.setOpen(true);\r
+                                                                                       selected.reload();\r
+                                                                               }, this);\r
+                                                               // bundleService.send();\r
+                                                               // Do not send, not implemented yet, false timer\r
+                                                               // instead.\r
+                                                               qx.event.Timer.once(function(response) {\r
+                                                                                       selected.setEnabled(true);\r
+                                                                                       selected.setOpen(true);\r
+                                                                                       selected.reload();\r
+                                                                               }, this, 2000);\r
+                                                       } else {\r
+                                                               selected.reload();\r
+                                                       }\r
+                                               }\r
+                                       },\r
+                                       selectionChange : function(viewId, selection) {\r
+                                               if (viewId != "form:tree")\r
+                                                       return;\r
+                                               if (!selection)\r
+                                                       return;\r
+                                               if (selection.length > 1) {\r
+                                                       this.setEnabled(false);\r
+                                                       return;\r
+                                               }\r
+                                               var item = selection[0];\r
+                                               if (!qx.Class.isSubClassOf(qx.Class\r
+                                                                               .getByName(item.classname),\r
+                                                               qx.ui.tree.AbstractTreeItem))\r
+                                                       return;\r
+                                               this.setEnabled(false);\r
+                                               if (qx.Class.isSubClassOf(qx.Class\r
+                                                                               .getByName(item.classname),\r
+                                                               org.argeo.ria.components.DynamicTreeFolder)) {\r
+                                                       this.setEnabled(true);\r
+                                               }\r
+                                       },\r
+                                       command : null\r
+                               }\r
+                       }\r
+               }\r
+       },\r
+\r
+       statics : {\r
+               /**\r
+                * Static loader for the "agent" level (first level)\r
+                * \r
+                * @param folder\r
+                *            {qx.ui.tree.TreeFolder} The root Tree Folder.\r
+                */\r
+               agentLoader : function(folder) {\r
+\r
+                       var req = org.argeo.slc.ria.SlcApi.getListAgentsService("agents");                      \r
+                       var agents = {};\r
+                       if(folder.getState() == "loaded" && folder.getUserData("agentsMap")){\r
+                               // Diff loading, just add new nodes.\r
+                               agents = folder.getUserData("agentsMap");\r
+                               var newAgents = {};\r
+                       }\r
+                       req.addListener("completed", function(response) {\r
+                               var xmlDoc = response.getContent();\r
+                               var nodes = org.argeo.ria.util.Element.selectNodes(xmlDoc,\r
+                                               "//slc:slc-agent-descriptor");\r
+                               var modulesLoader = org.argeo.slc.ria.FlowsSelectorView.modulesLoader;\r
+                               \r
+                               for (var i = 0; i < nodes.length; i++) {\r
+                                       var uuid = org.argeo.ria.util.Element.getSingleNodeText(\r
+                                                       nodes[i], "@uuid");\r
+                                       if(agents[uuid]){\r
+                                               newAgents[uuid] = host;\r
+                                               continue;\r
+                                       }\r
+                                       var host = org.argeo.ria.util.Element.getSingleNodeText(nodes[i], "slc:host");\r
+                                       agents[uuid] = host;\r
+                                       if(newAgents) newAgents[uuid] = host;\r
+                                       var agentFolder = new org.argeo.ria.components.DynamicTreeFolder(\r
+                                                       host + ' (' + uuid + ')', modulesLoader,\r
+                                                       "Loading Modules...", folder.getDragData());\r
+                                       agentFolder.setUserData("agentUuid", uuid);\r
+                                       agentFolder.setIcon("resource/slc/mime-xsl-22.png");\r
+                                       folder.add(agentFolder);\r
+                               }\r
+                               if(newAgents){\r
+                                       // Make sure some agents should not be removed\r
+                                       for(var agentKey in agents){\r
+                                               if(!newAgents[agentKey]){\r
+                                                       var node = org.argeo.slc.ria.FlowsSelectorView.findAgentNodeById(folder, agentKey);\r
+                                                       if(node) folder.remove(node);\r
+                                                       delete agents[agentKey];\r
+                                                       var batchView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("batch").getContent();\r
+                                                       if(batchView) batchView.clearBatchForAgentId(agentKey);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               folder.setUserData("agentsMap", agents);\r
+                               folder.setLoaded(true);\r
+                               folder.getTree().fireEvent("changeSelection");                          \r
+                       });\r
+                       req.addListener("failed", function(response) {\r
+                                               folder.setLoaded(true);\r
+                                       });\r
+                       req.send();\r
+\r
+               },\r
+\r
+               /**\r
+                * Loader for the "modules" level : takes any tree folder, currently the\r
+                * root folder.\r
+                * \r
+                * @param folder\r
+                *            {qx.ui.tree.TreeFolder} The root folder\r
+                */\r
+               modulesLoader : function(folder) {\r
+                       var agentId = folder.getUserData("agentUuid");\r
+                       var req = org.argeo.slc.ria.SlcApi.getListModulesService(agentId);\r
+                       req.addListener("completed", function(response) {\r
+                               var descriptors = org.argeo.ria.util.Element.selectNodes(\r
+                                               response.getContent(),\r
+                                               "slc:object-list/slc:execution-module-descriptor");\r
+                               var mods = {};\r
+                               for (var i = 0; i < descriptors.length; i++) {\r
+                                       var name = org.argeo.ria.util.Element.getSingleNodeText(\r
+                                                       descriptors[i], "slc:name");\r
+                                       var version = org.argeo.ria.util.Element.getSingleNodeText(\r
+                                                       descriptors[i], "slc:version");\r
+                                       if (!mods[name])\r
+                                               mods[name] = [];\r
+                                       mods[name].push(version);\r
+                               }\r
+                               var flowLoader = org.argeo.slc.ria.FlowsSelectorView.flowLoader;\r
+                               for (var key in mods) {\r
+                                       for (var i = 0; i < mods[key].length; i++) {\r
+                                               var versionFolder = new org.argeo.ria.components.DynamicTreeFolder(\r
+                                                               key + ' (' + mods[key][i] + ')', flowLoader,\r
+                                                               "Loading Flows", folder.getDragData());\r
+                                               folder.add(versionFolder);\r
+                                               versionFolder.setUserData("moduleData", {\r
+                                                                       name : key,\r
+                                                                       version : mods[key][i]\r
+                                                               });\r
+                                               versionFolder.setUserData("agentUuid", agentId);\r
+                                       }\r
+                               }\r
+                               folder.setLoaded(true);\r
+                               folder.getTree().fireEvent("changeSelection");\r
+                       });\r
+                       req.addListener("failed", function(response) {\r
+                               folder.setLoaded(true);\r
+                       });\r
+                       req.send();\r
+               },\r
+\r
+               /**\r
+                * Loader for the "flow" level : takes a folder containing "moduleData"\r
+                * and create its children.\r
+                * \r
+                * @param folder\r
+                *            {qx.ui.tree.TreeFolder} A Tree folder containing in the\r
+                *            key "moduleData" of its user data a map containing the\r
+                *            keys {name,version}\r
+                */\r
+               flowLoader : function(folder) {\r
+                       var moduleData = folder.getUserData("moduleData");\r
+                       var agentUuid = folder.getUserData("agentUuid");\r
+\r
+                       var req = org.argeo.slc.ria.SlcApi\r
+                                       .getLoadExecutionDescriptorService(agentUuid,\r
+                                                       moduleData.name, moduleData.version);\r
+                       req.addListener("completed", function(response) {\r
+                               var executionModule = new org.argeo.slc.ria.execution.Module();\r
+                               try {\r
+                                       executionModule.setXmlNode(response.getContent());\r
+                               } catch (e) {\r
+                                       this.error(e);\r
+                               }\r
+                               var execFlows = executionModule.getExecutionFlows();\r
+                               for (var key in execFlows) {\r
+                                       var file = new qx.ui.tree.TreeFile(key);\r
+                                       var path = execFlows[key].getPath();\r
+                                       file.setUserData("executionModule",     executionModule);\r
+                                       file.setUserData("executionFlow", execFlows[key]);\r
+                                       file.setUserData("agentUuid", agentUuid);\r
+                                       org.argeo.slc.ria.FlowsSelectorView.attachNodeByPath(folder, path, file, {\r
+                                               agentUuid : folder.getUserData("agentUuid")\r
+                                       });\r
+                                       folder.appendDragData(file);\r
+                               }\r
+                               folder.setLoaded(true);\r
+                               folder.getTree().fireEvent("changeSelection");\r
+                       });\r
+                       req.addListener("failed", function(response) {\r
+                               folder.setLoaded(true);\r
+                       });\r
+                       req.send();\r
+               },\r
+\r
+               /**\r
+                * Parse a string path and search if there is a root node.\r
+                * \r
+                * @param rootNode\r
+                *            {org.argeo.ria.components.DynamicTreeFolder} The parent\r
+                *            node (containing data model)\r
+                * @param path\r
+                *            {String} The path of the node to attach.\r
+                * @param childNode\r
+                *            {qx.ui.tree.TreeFile} The leaf node\r
+                * @param userData\r
+                *            {Map} User data to attach at all levels.\r
+                */\r
+               attachNodeByPath : function(rootNode, path, childNode, userData) {\r
+                       if (!path || path == "" || path == "/") {\r
+                               rootNode.add(childNode);\r
+                               return;\r
+                       }\r
+                       var model = rootNode.getUserData("dataModel");\r
+                       if (!model) {\r
+                               model = {};\r
+                               rootNode.setUserData("dataModel", model);\r
+                       }\r
+                       var parts = path.split("/");\r
+                       var keys = qx.lang.Object.getKeys(model);\r
+                       var crtPath = "";\r
+                       var crtFolder = rootNode;                       \r
+                       for (var i = 0; i < parts.length; i++) {\r
+                               if (parts[i] == "")\r
+                                       continue;\r
+                               crtPath += "/" + parts[i];                              \r
+                               if (!model[crtPath]) {\r
+                                       var virtualFolder = new qx.ui.tree.TreeFolder(parts[i]);\r
+                                       if (userData && qx.lang.Object.getLength(userData)) {\r
+                                               for (var key in userData) {\r
+                                                       virtualFolder.setUserData(key, userData[key]);\r
+                                               }\r
+                                       }\r
+                                       rootNode.appendDragData(virtualFolder);\r
+                                       model[crtPath] = virtualFolder;\r
+                                       crtFolder.add(virtualFolder);\r
+                                       crtFolder = virtualFolder;\r
+                               } else {\r
+                                       crtFolder = model[crtPath];\r
+                               }\r
+                       }\r
+                       crtFolder.add(childNode);\r
+               },\r
+               \r
+               findAgentNodeById : function(node, agentId){\r
+                       var nodeAgents = node.getItems();\r
+                       for(var i=0;i<nodeAgents.length;i++){\r
+                               if(nodeAgents[i].getUserData("agentUuid") == agentId){\r
+                                       return nodeAgents[i];\r
+                               }\r
+                       }\r
+               }               \r
+       },\r
+\r
+       members : {\r
+               /**\r
+                * Called at applet creation. Just registers viewPane.\r
+                * \r
+                * @param viewPane\r
+                *            {org.argeo.ria.components.ViewPane} The viewPane.\r
+                */\r
+               init : function(viewPane) {\r
+                       this.setView(viewPane);\r
+                       this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId()));\r
+                       this.remoteNotifier = new org.argeo.ria.remote.RemoteNotifier(\r
+                                       "/org.argeo.slc.webapp/", "pollEvent.service",\r
+                                       "addEventListener.service", "removeEventListener.service");\r
+                       this.remoteNotifier.setEventParamName("slc_eventType");\r
+                       this.remoteNotifier.setEventXPath("/slc:slc-event");\r
+                       this.remoteNotifier\r
+                                       .setEventTypeXPath('slc:headers/slc:header[@name="slc_eventType"]');\r
+                       this.remoteNotifier\r
+                                       .setEventDataXPath('slc:headers/slc:header[@name="slc_agentId"]');\r
+                       this.remoteNotifier.startPolling();\r
+                       this.UIBus = org.argeo.ria.event.UIBus.getInstance();\r
+                       this.UIBus.registerNotifier(this.remoteNotifier);\r
+               },\r
+\r
+               /**\r
+                * \r
+                */\r
+               load : function() {\r
+                       this._createLayout();\r
+                       this.getView().setViewTitle("Available Scripts");\r
+                       this.UIBus.addListener("agentRegistered", this._addAgentHandler, this);\r
+                       this.UIBus.addListener("agentUnregistered", this._removeAgentHandler,   this);\r
+               },\r
+\r
+               _addAgentHandler : function(agentId){\r
+                       this.rootNode.load();\r
+               },\r
+               \r
+               _removeAgentHandler : function(agentId){\r
+                       var treeNode = this.self(arguments).findAgentNodeById(this.rootNode, agentId);\r
+                       if(treeNode){\r
+                               this.rootNode.remove(treeNode);\r
+                       }\r
+                       var agentsMap = this.getAgentsMap();\r
+                       if(agentsMap[agentId]){                         \r
+                               delete agentsMap[agentId];\r
+                       }\r
+                       var batchView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("batch").getContent();\r
+                       if(batchView){\r
+                               batchView.clearBatchForAgentId(agentId);\r
+                       }\r
+               },\r
+               \r
+               addScroll : function() {\r
+                       return false;\r
+               },\r
+\r
+               close : function() {\r
+                       this.UIBus.removeListener("agentRegistered", this._addAgentHandler, this);\r
+                       this.UIBus.removeListener("agentUnregistered", this._removeAgentHandler, this);\r
+                       this.remoteNotifier.stopPolling();\r
+               },\r
+\r
+               /**\r
+                * Creates the main applet layout.\r
+                */\r
+               _createLayout : function() {\r
+\r
+                       this.tree = new qx.ui.tree.Tree();\r
+                       this.tree.setDecorator(null);\r
+                       this.tree.setSelectionMode("multi");\r
+                       var dragData = {\r
+                               "file" : {\r
+                                       "type" : ["items"],\r
+                                       "action" : ["move"]\r
+                               },\r
+                               "folder" : {\r
+                                       "type" : ["items"],\r
+                                       "action" : ["move"]\r
+                               }\r
+                       };\r
+\r
+                       this.rootNode = new org.argeo.ria.components.DynamicTreeFolder(\r
+                                       "Tests", this.self(arguments).agentLoader,\r
+                                       "Loading Agents", dragData);\r
+                       this.tree.setRoot(this.rootNode);\r
+                       this.rootNode.setOpen(true);\r
+                       this.tree.setContextMenu(org.argeo.ria.event.CommandsManager\r
+                                       .getInstance().createMenuFromIds(["addtobatch",\r
+                                                       "reloadtree"]));\r
+\r
+                       this.tree.addListener("changeSelection", function(e) {\r
+                               var viewSelection = this.getViewSelection();\r
+                               viewSelection.setViewId("form:tree");\r
+                               viewSelection.clear();\r
+                               var sel = this.tree.getSortedSelection();\r
+                               for (var i = 0; i < sel.length; i++) {\r
+                                       viewSelection.addNode(sel[i]);\r
+                               }\r
+                       }, this);\r
+\r
+\r
+                       this.add(this.tree);\r
+               },\r
+               \r
+               getAgentsMap : function(){\r
+                       return this.rootNode.getUserData("agentsMap");\r
+               }               \r
+       }\r
+});
\ No newline at end of file