From: Mathieu Baudier Date: Thu, 23 Apr 2009 16:34:59 +0000 (+0000) Subject: Move to src X-Git-Tag: argeo-slc-2.1.7~1984 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=d8e9131cdd34b663a03008df8eb97616694259ce;hp=9b1896a43d37f6f58374a732fd23912fd26a6cf3;p=gpl%2Fargeo-slc.git Move to src git-svn-id: https://svn.argeo.org/slc/trunk@2331 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/Manifest.json b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/Manifest.json new file mode 100644 index 000000000..e823935a5 --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/Manifest.json @@ -0,0 +1,34 @@ +{ + "info" : + { + "name" : "org.argeo.ria.sample", + + "summary" : "Sample RIA Application", + "description" : "Basic RIA Implementation for documentation purposes", + + "homepage" : "http://www.argeo.org/", + + "license" : "LGPL", + "authors" : + [ + { + "name" : "Charles du Jeu", + "email" : "charles.dujeu@gmail.com" + } + ], + + "version" : "trunk", + "qooxdoo-versions": ["0.8"] + }, + + "provides" : + { + "namespace" : "org.argeo.ria.sample", + "encoding" : "utf-8", + "class" : "class", + "resource" : "resource", + "translation" : "translation", + "type" : "library" + } +} + diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/Applet.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/Applet.js new file mode 100644 index 000000000..4baad35a9 --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/Applet.js @@ -0,0 +1,97 @@ +/** + * A simple Hello World applet for documentation purpose. + * The only associated command is the "Close" command. + */ +qx.Class.define("org.argeo.ria.sample.Applet", +{ + extend : qx.ui.container.Composite, + implement : [org.argeo.ria.components.IView], + + construct : function(){ + this.base(arguments); + this.setLayout(new qx.ui.layout.VBox()); + this.passedStatus = "PASSED"; + this.failedStatus = "FAILED"; + }, + + properties : + { + /** + * The viewPane inside which this applet is added. + */ + view : { + init : null + }, + /** + * Commands definition, see {@link org.argeo.ria.event.CommandsManager#definitions} + */ + commands : { + init : { + "close" : { + label : "Close Result", + icon : "resource/slc/window-close.png", + shortcut : "Control+w", + enabled : true, + menu : "Applet", + toolbar : "result", + callback : function(e){ + // Call service to delete + this.getView().empty(); + }, + command : null + } + } + }, + viewSelection : { + nullable:false, + check:"org.argeo.ria.components.ViewSelection" + }, + instanceId : {init:"Hello Applet"}, + instanceLabel : {init:"Hello"} + + }, + + members : + { + /** + * Called at applet creation. Just registers viewPane. + * @param viewPane {org.argeo.ria.components.ViewPane} The viewPane. + */ + init : function(viewPane, data){ + this.setView(viewPane); + this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId())); + this.data = data; + this.setInstanceId(data[0]); + this.setInstanceLabel("Hello applet #"+data[0]); + }, + + /** + * Load a given row : the data passed must be a simple data array. + * @param data {Element} The text xml description. + */ + load : function(){ + this.createHtmlGui("Hello World ! Data ID is : "+this.getInstanceId()+""); + }, + + addScroll : function(){ + return false; + }, + + close : function(){ + return false; + }, + + /** + * Create a simple HtmlElement and and insert the html string.. + * Not used but sample. + * @param htmlText {String} Html code to display. + */ + createHtmlGui : function(htmlText){ + var htmlElement = new qx.ui.embed.Html(htmlText); + htmlElement.setOverflowX("auto"); + htmlElement.setOverflowY("auto"); + this.add(htmlElement, {flex:1}); + } + + } +}); \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/List.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/List.js new file mode 100644 index 000000000..ad3ef5c9b --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/List.js @@ -0,0 +1,123 @@ +/** + * A Basic IView implementation displaying a fake list of result and opening + * an org.argeo.ria.sample.Applet + */ +qx.Class.define("org.argeo.ria.sample.List", +{ + extend : qx.ui.container.Composite, + implement : [org.argeo.ria.components.IView], + + construct : function(){ + this.base(arguments, new qx.ui.layout.VBox()); + var model = new qx.ui.table.model.Simple(); + model.setColumns(["Test Case", "Date"]); + this.table = new qx.ui.table.Table(model, { + tableColumnModel: function(obj){ + return new qx.ui.table.columnmodel.Resize(obj) + } + }); + }, + + properties : + { + /** + * The viewPane containing this applet. + */ + view : { + init : null + }, + /** + * The applet commands. + */ + commands : { + init : { + "opentest" : { + label : "Open", + icon : "resource/slc/media-playback-start.png", + shortcut : "Control+o", + enabled : false, + menu : "Selection", + toolbar : "selection", + callback : function(e){ + var viewsManager = org.argeo.ria.components.ViewsManager.getInstance(); + var classObj = org.argeo.ria.sample.Applet; + var rowData = viewsManager.getViewPaneSelection("list").getNodes(); + var iView = viewsManager.initIViewClass(classObj, "applet", rowData[0]); + iView.load(); + }, + selectionChange : function(viewId, rowData){ + if(viewId != "list") return; + this.setEnabled(false); + if(rowData == null || !rowData.length) return; + this.setEnabled(true); + }, + command : null + } + } + }, + viewSelection : { + nullable:false, + check:"org.argeo.ria.components.ViewSelection" + }, + instanceId : {init:"0"}, + instanceLabel : {init:"Sample List"} + }, + + members : { + init : function(viewPane, data){ + this.setView(viewPane); + this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId())); + + }, + load : function(){ + // + // Customize table appearance + // + this.table.set({ + statusBarVisible: false, + showCellFocusIndicator:false, + columnVisibilityButtonVisible:false, + contextMenu : org.argeo.ria.event.CommandsManager.getInstance().createMenuFromIds(["opentest", "download", "copytocollection", "deletetest"]), + decorator : new qx.ui.decoration.Background("#fff") + }); + + // + // Link table selection changes to the standard viewSelection mechanism + // + var selectionModel = this.table.getSelectionManager().getSelectionModel(); + selectionModel.addListener("changeSelection", function(e){ + var viewSelection = this.getViewSelection(); + viewSelection.clear(); + if(!selectionModel.getSelectedCount()){ + return; + } + var ranges = selectionModel.getSelectedRanges(); + var rowData = this.table.getTableModel().getRowData(ranges[0].minIndex); + viewSelection.addNode(rowData); + }, this); + + // + // Add table to the GUI component + // + this.add(this.table, {flex:1}); + + // + // Now create fake rows + // + var model = this.table.getTableModel(); + model.addRows([ + ["Id 1","Sample 1"], + ["Id 2","Sample 2"], + ["Id 3","Sample 3"] + ]); + }, + + addScroll : function(){ + return false; + }, + + close : function(){ + + } + } +}); \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/Perspective.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/Perspective.js new file mode 100644 index 000000000..de01afc73 --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/Perspective.js @@ -0,0 +1,47 @@ +/** + * IPerspective Implementation : Horizontal split pane defining two panes, "list" and "applet". + */ +qx.Class.define("org.argeo.ria.sample.Perspective", +{ + extend : qx.core.Object, + implement : [org.argeo.ria.components.IPerspective], + + construct : function(){ + this.base(arguments); + }, + + members : { + + initViewPanes : function(viewsManager){ + + this.splitPane = new qx.ui.splitpane.Pane("horizontal"); + var topLeft = new org.argeo.ria.components.ViewPane("list", "Sample List", { + orientation : "horizontal", + min : 36 + }); + topLeft.set({width:300}); + viewsManager.registerViewPane(topLeft); + + this.splitPane.add(topLeft, 0); + var rightPane = new org.argeo.ria.components.ViewPane("applet", "Sample Applet"); + viewsManager.registerViewPane(rightPane); + this.splitPane.add(rightPane, 1); + + viewsManager.getViewPanesContainer().add(this.splitPane, {flex:1}); + + }, + + initViews : function(viewsManager){ + var view = viewsManager.initIViewClass(org.argeo.ria.sample.List, "list"); + view.load(); + }, + + remove : function(viewsManager){ + viewsManager.getViewPaneById("list").empty(); + viewsManager.getViewPaneById("applet").empty(); + viewsManager.getViewPanesContainer().remove(this.splitPane); + } + + } + +}); \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/__init__.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/__init__.js new file mode 100644 index 000000000..009514690 --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/sample/class/org/argeo/ria/sample/__init__.js @@ -0,0 +1,3 @@ +/** + * Specific classes used for training by the Argeo RIA documentation + */ \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/Manifest.json b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/Manifest.json new file mode 100644 index 000000000..ed1705eed --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/Manifest.json @@ -0,0 +1,34 @@ +{ + "info" : + { + "name" : "org.argeo.slc.web", + + "summary" : "Slc Web Application", + "description" : "RIA Implementation for SLC Web", + + "homepage" : "http://www.argeo.org/", + + "license" : "LGPL", + "authors" : + [ + { + "name" : "Charles du Jeu", + "email" : "charles.dujeu@gmail.com" + } + ], + + "version" : "trunk", + "qooxdoo-versions": ["0.8"] + }, + + "provides" : + { + "namespace" : "org.argeo.slc.web", + "encoding" : "utf-8", + "class" : "class", + "resource" : "resource", + "translation" : "translation", + "type" : "library" + } +} + diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/LauncherPerspective.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/LauncherPerspective.js new file mode 100644 index 000000000..8fb95ab80 --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/LauncherPerspective.js @@ -0,0 +1,58 @@ +/** + * IPerspective Implementation : Horizontal split pane defining two panes, "list" and "applet". + */ +qx.Class.define("org.argeo.slc.web.LauncherPerspective", +{ + extend : qx.core.Object, + implement : [org.argeo.ria.components.IPerspective], + + construct : function(){ + this.base(arguments); + org.argeo.ria.util.Element.DEFAULT_NAMESPACE_MAP = {slc:"http://argeo.org/projects/slc/schemas"}; + }, + + statics : { + LABEL : "Slc Execution", + ICON : "resource/slc/utilities-terminal.png" + }, + + members : { + + _rightPane : null, + + initViewPanes : function(viewsManager){ + + this._splitPane = new qx.ui.splitpane.Pane("horizontal"); + var topLeft = new org.argeo.ria.components.ViewPane("form", "Execution Launcher", { + orientation : "horizontal", + min : 36 + }); + topLeft.set({width:290}); + viewsManager.registerViewPane(topLeft); + + this._splitPane.add(topLeft, 0); + var rightPane = new org.argeo.ria.components.ViewPane("main", "Executions Log"); + viewsManager.registerViewPane(rightPane); + this._splitPane.add(rightPane, 1); + + viewsManager.getViewPanesContainer().add(this._splitPane, {flex:1}); + + }, + + initViews : function(viewsManager){ + var formApplet = viewsManager.initIViewClass(org.argeo.slc.ria.NewLauncherApplet, "form"); + formApplet.load(); + + var logger = viewsManager.initIViewClass(org.argeo.slc.ria.SlcExecLoggerApplet, "main"); + logger.load(); + }, + + remove : function(viewsManager){ + viewsManager.getViewPaneById("main").empty(); + viewsManager.getViewPaneById("form").empty(); + viewsManager.getViewPanesContainer().remove(this._splitPane); + } + + } + +}); \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/Perspective.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/Perspective.js new file mode 100644 index 000000000..21a808a86 --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/Perspective.js @@ -0,0 +1,56 @@ +/** + * IPerspective Implementation : Horizontal split pane defining two panes, "list" and "applet". + */ +qx.Class.define("org.argeo.slc.web.Perspective", +{ + extend : qx.core.Object, + implement : [org.argeo.ria.components.IPerspective], + + construct : function(){ + this.base(arguments); + org.argeo.ria.util.Element.DEFAULT_NAMESPACE_MAP = {slc:"http://argeo.org/projects/slc/schemas"}; + }, + + statics : { + LABEL : "Test Results", + ICON : "resource/slc/office-chart.png" + }, + + members : { + _splitPane : null, + + initViewPanes : function(viewsManager){ + + this._splitPane = new qx.ui.splitpane.Pane("horizontal"); + var topLeft = new org.argeo.ria.components.ViewPane("list", "Collection", { + orientation : "horizontal", + min : 36 + }); + topLeft.set({width:300}); + viewsManager.registerViewPane(topLeft); + + this._splitPane.add(topLeft, 0); + var rightPane = new org.argeo.ria.components.TabbedViewPane("applet", "Test Detail"); + viewsManager.registerViewPane(rightPane); + this._splitPane.add(rightPane, 1); + + viewsManager.getViewPanesContainer().add(this._splitPane, {flex:1}); + + }, + + initViews : function(viewsManager){ + var view = viewsManager.initIViewClass(org.argeo.slc.web.TestList, "list"); + view.load(); + view.loadCollections(); + view.loadList(); + }, + + remove : function(viewsManager){ + viewsManager.getViewPaneById("list").empty(); + viewsManager.getViewPaneById("applet").empty(); + viewsManager.getViewPanesContainer().remove(this._splitPane); + } + + } + +}); \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/TestList.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/TestList.js new file mode 100644 index 000000000..28a9f193c --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc-web/class/org/argeo/slc/web/TestList.js @@ -0,0 +1,459 @@ +/** + * Basic IView implementation for displaying the test results list, by collection. + * + * This component creates a Table object and feed it with the results. It adds a collection chooser to its viewPane header. + * + * It creates the following commands : "loadtestlist", "polllistloading", "opentest", "download", "copytocollection", "deletetest". + */ +qx.Class.define("org.argeo.slc.web.TestList", +{ + extend : qx.ui.container.Composite, + implement : [org.argeo.ria.components.IView], + + construct : function(){ + this.base(arguments, new qx.ui.layout.VBox()); + var model = new qx.ui.table.model.Simple(); + model.setColumns(["Test Case", "Date"]); + this.table = new qx.ui.table.Table(model, { + tableColumnModel: function(obj){ + return new qx.ui.table.columnmodel.Resize(obj) + } + }); + }, + + properties : + { + /** + * The viewPane containing this applet. + */ + view : { + init : null + }, + viewSelection : { + nullable:false, + check:"org.argeo.ria.components.ViewSelection" + }, + instanceId : {init:""}, + instanceLabel : {init:""}, + /** + * The load list of available collection (Map of ids => labels) + */ + collectionList : { + init : {}, + check : "Map" + }, + /** + * The current collection id selected. + */ + collectionId:{ + init : 'My Collection', + check : "String" + }, + /** + * The applet commands. + */ + commands : { + init : { + "loadtestlist" : { + label : "Load Collection", + icon : "resource/slc/view-refresh.png", + shortcut : "Control+l", + enabled : true, + menu : "Collection", + toolbar : "collection", + callback : function(e){ + this.loadList(); + }, + command : null + }, + "polllistloading" : { + label : "Auto load", + icon : "resource/slc/document-open-recent.png", + shortcut : "Control+l", + enabled : true, + toggle : true, + menu : "Collection", + toolbar : "collection", + callback : function(event){ + this.pollListLoading(event.getTarget().getUserData("slc.command.toggleState")); + }, + command : null + }, + /* + "copyfullcollection" : { + label : "Copy to...", + icon : "resource/slc/edit-copy.png", + shortcut : null, + enabled : false, + menu : "Collection", + toolbar : "collection", + callback : function(e){ + // Call service to copy + }, + submenu : {}, + submenuCallback : function(commandId){ + this.copySelectionToCollection(commandId, "current_collection"); + }, + init : function(){ + // Call at command creation + org.argeo.ria.remote.RequestManager.getInstance().addListener("reload", function(event){ + if(event.getDataType() == "collection" || event.getDataType() == "test_cases"){ + var testList = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("list").getContent(); + testList.collectionListToMenu(this); + } + }, this); + }, + command : null + }, + */ + "opentest" : { + label : "Open", + icon : "resource/slc/media-playback-start.png", + shortcut : "Control+o", + enabled : false, + menu : "Selection", + toolbar : "selection", + callback : function(e){ + var viewsManager = org.argeo.ria.components.ViewsManager.getInstance(); + var classObj = org.argeo.slc.ria.Applet; + var xmlNodes = viewsManager.getViewPaneSelection("list").getNodes(); + var iView = viewsManager.initIViewClass(classObj, "applet", xmlNodes[0]); + iView.load(xmlNodes[0]); + }, + selectionChange : function(viewId, xmlNodes){ + if(viewId != "list") return; + this.setEnabled(false); + if(xmlNodes == null || !xmlNodes.length) return; + this.setEnabled(true); + }, + command : null + }, + "download" : { + label : "Download as...", + icon : "resource/slc/go-down.png", + shortcut : null, + enabled : false, + menu : "Selection", + toolbar : "selection", + callback : function(e){ }, + command : null, + submenu : [ + {'label':"Xsl", 'icon':'resource/slc/mime-xsl.png', 'commandId':'xsl'}, + {'label':"Xml", 'icon':'resource/slc/mime-xml.png', 'commandId':'xml'}, + {'label':"Excel", 'icon':'resource/slc/mime-xls.png', 'commandId':'xls'}, + {'label':"Pdf", 'icon':'resource/slc/mime-pdf.png', 'commandId':'pdf'} + ], + submenuCallback : function(commandId){ + var uuid = this.extractTestUuid(); + var urls = { + xsl : "resultView.xslt", + xml : "resultViewXml.xslt", + xls : "resultView.xls", + pdf : "resultView.pdf" + }; + var url = "../"+urls[commandId]+"?uuid="+uuid; + if(commandId == "xls" || commandId == "pdf"){ + document.location.href = url; + }else{ + var win = window.open(url); + } + }, + selectionChange : function(viewId, xmlNodes){ + if(viewId!="list")return; + //this.clearMenus(); + this.setEnabled(false); + if(xmlNodes == null || !xmlNodes.length) return; + this.setEnabled(true); + } + }, + "copytocollection" : { + label : "Copy to...", + icon : "resource/slc/edit-copy.png", + shortcut : "Control+c", + enabled : false, + menu : "Selection", + toolbar : "selection", + callback : function(e){ + // Call service to copy + }, + submenu : {}, + submenuCallback : function(commandId){ + this.copySelectionToCollection(commandId, "current_selection"); + }, + init : function(){ + // Call at command creation + org.argeo.ria.remote.RequestManager.getInstance().addListener("reload", function(event){ + if(event.getDataType() == "collection" || event.getDataType() == "test_cases"){ + var testList = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("list").getContent(); + testList.collectionListToMenu(this, true); + } + }, this); + }, + selectionChange : function(viewId, xmlNodes){ + if(viewId != "list") return; + this.setEnabled(false); + if(xmlNodes == null || !xmlNodes.length) return; + this.setEnabled(true); + }, + command : null + }, + "deletetest" : { + label : "Delete", + icon : "resource/slc/edit-delete.png", + shortcut : "Control+d", + enabled : false, + menu : "Selection", + toolbar : "selection", + callback : function(e){ + var modal = new org.argeo.ria.components.Modal("Confirm", null); + modal.addConfirm("Are you sure you want to delete
test " + this.extractTestUuid() + "?"); + modal.addListener("ok", function(){ + var request = org.argeo.slc.ria.SlcApi.getRemoveResultService(this.getCollectionId(), this.extractTestUuid()); + request.addListener("completed", function(response){ + this.loadCollections(); + this.loadList(); + this.info("Test was successfully deleted"); + }, this); + request.send(); + }, this); + modal.attachAndShow(); + }, + selectionChange : function(viewId, xmlNodes){ + if(viewId != "list") return; + this.setEnabled(false); + if(xmlNodes == null || !xmlNodes.length) return; + this.setEnabled(true); + }, + command : null + } + } + } + }, + + members : { + init : function(viewPane, data){ + this.setView(viewPane); + this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId())); + }, + load : function(){ + this.table.set({ + statusBarVisible: false, + showCellFocusIndicator:false, + columnVisibilityButtonVisible:false, + contextMenu : org.argeo.ria.event.CommandsManager.getInstance().createMenuFromIds(["opentest", "download", "copytocollection", "deletetest"]), + decorator : new qx.ui.decoration.Background("#fff") + }); + var viewPane = this.getView(); + this.table.addListener("dblclick", function(e){ + org.argeo.ria.event.CommandsManager.getInstance().executeCommand("opentest"); + }, this); + var columnModel = this.table.getTableColumnModel(); + columnModel.getBehavior().setWidth(0, "60%"); + var renderer = new org.argeo.slc.web.XmlRenderer(); + columnModel.setDataCellRenderer(0, renderer); + columnModel.setDataCellRenderer(1, renderer); + + this.table.getSelectionManager().getSelectionModel().addListener("changeSelection", function(e){ + var viewSelection = this.getViewSelection(); + viewSelection.clear(); + var selectionModel = this.table.getSelectionManager().getSelectionModel(); + if(!selectionModel.getSelectedCount()){ + return; + } + var ranges = this.table.getSelectionManager().getSelectionModel().getSelectedRanges(); + var xmlNode = this.table.getTableModel().getRowData(ranges[0].minIndex); + viewSelection.addNode(xmlNode); + //viewPane.setViewSelection(viewSelection); + }, this); + + var select = new qx.ui.form.SelectBox(); + this.getView().addHeaderComponent(select); + this.getView().setViewTitle(""); + this.add(this.table, {flex:1}); + + select.addListener("changeValue", this.collectionSelectorListener, this); + + org.argeo.ria.remote.RequestManager.getInstance().addListener("reload", function(event){ + if(event.getDataType()!="collection") return; + select.removeListener("changeValue", this.collectionSelectorListener, this); + var collectionList = event.getContent(); + select.removeAll(); + for(key in collectionList){ + var item = new qx.ui.form.ListItem(collectionList[key], "resource/slc/folder.png", key); + select.add(item); + if(key == this.getCollectionId()){ + select.setSelected(item); + } + } + if(qx.lang.Object.getLength(collectionList)){ + this.setCollectionId(select.getSelected().getValue()); + } + select.addListener("changeValue", this.collectionSelectorListener, this); + }, this); + + }, + + /** + * Use SlcApi to load the available collections. + */ + loadCollections : function(){ + var request = org.argeo.slc.ria.SlcApi.getListCollectionsService(); + var NSMap = {slc:"http://argeo.org/projects/slc/schemas"}; + request.addListener("completed", function(response){ + var xml = response.getContent(); + var collections = {}; + var nodes = org.argeo.ria.util.Element.selectNodes(xml, "//slc:ref", NSMap); + for(var i=0;i 1){ + // Add chooser + this.partChooser = new qx.ui.form.SelectBox(); + for(var key in this.parts){ + this.partChooser.add(new qx.ui.form.ListItem(this.parts[key].label, null, key)); + } + this._addFormEntry(commonForm, new qx.ui.basic.Label(this.CHOOSE_FORM_PART_LABEL), this.partChooser); + this.partChooser.addListener("changeValue", function(ev){ + this._showSelectedPart(ev.getData()); + }, this); + } + this._showSelectedPart(qx.lang.Object.getKeys(this.parts)[0]); + }, + + /** + * Show a form part given its id. + * @param partId {String} The part id + */ + _showSelectedPart : function(partId){ + if(!this.parts) return; + if(!this.partsContainer){ + this.partsContainer = new qx.ui.container.Composite(new qx.ui.layout.Canvas()); + this.formPane.add(this.partsContainer); + } + for(var i in this.parts){ + var formObject = this.parts[i]; + if(!formObject.added){ + this.partsContainer.add(formObject.pane, {top:0, left:0}); + formObject.added = true; + } + formObject.pane.hide(); + } + if(this.parts[partId]){ + this.parts[partId].pane.show(); + } + }, + + /** + * Init a form part : creates a pane, a set of fields, etc. + * @param formId {String} A unique ID + * @param label {String} A label + * @return {Map} The form part. + */ + _initFormPart : function(formId, label){ + if(!this.parts) this.parts = {}; + var formObject = {}; + formObject.hiddenFields = {}; + formObject.freeFields = []; + formObject.fields = {}; + formObject.id = formId; + formObject.label = label; + this.parts[formId] = formObject; + formObject.pane = new qx.ui.container.Composite(new qx.ui.layout.VBox(5)); + return formObject; + }, + + /** + * To be overriden by this class children. + */ + _createFormVariableParts : function(){ + var standard = this._initFormPart("standard", "Canonical"); + this._createStandardForm(standard); + var simple = this._initFormPart("simple", "SLC Sample"); + this._createSimpleForm(simple); + }, + + /** + * Creates a form for SLC demo + * @param formObject {Map} The form part + */ + _createSimpleForm : function(formObject){ + + this._addFormInputText(formObject, "ant.file", "File", "Category1/SubCategory2/build.xml"); + var moreButton = new qx.ui.basic.Image("resource/slc/list-add.png"); + moreButton.setToolTip(new qx.ui.tooltip.ToolTip("Add a parameter")); + moreButton.setCursor("pointer"); + moreButton.addListener("click", function(){ + this._addFormInputText(formObject); + }, this); + this._addFormHeader(formObject, "Add optionnal parameters", moreButton); + this._addFormInputText(formObject); + this._addFormInputText(formObject); + + }, + + /** + * Create a canonical form. + * @param formObject {Map} The form part + */ + _createStandardForm : function(formObject){ + + this._addFormHeader(formObject, "Set Execution Parameters"); + this._addFormInputText(formObject, "status", "Status", "STARTED"); + this._addFormInputText(formObject, "host", "Host", "localhost"); + this._addFormInputText(formObject, "user", "User", "user"); + + var moreButton = new qx.ui.basic.Image("resource/slc/list-add.png"); + moreButton.setToolTip(new qx.ui.tooltip.ToolTip("Add a parameter")); + moreButton.setCursor("pointer"); + moreButton.addListener("click", function(){ + this._addFormInputText(formObject); + }, this); + this._addFormHeader(formObject, "Add optionnal parameters", moreButton); + this._addFormInputText(formObject); + this._addFormInputText(formObject); + }, + + /** + * Add an hidden field to the form + * @param formObject {Map} The form part + * @param fieldName {String} Name + * @param fieldValue {String} Value + */ + _addFormHiddenField : function(formObject, fieldName, fieldValue){ + formObject.hiddenFields[fieldName] = fieldValue; + }, + + /** + * Creates a simple label/input form entry. + * @param formObject {Map} The form part + * @param fieldName {String} Name + * @param fieldLabel {String} Label of the field + * @param defaultValue {String} The default value + * @param choiceValues {Map} An map of values + */ + _addFormInputText : function(formObject, fieldName, fieldLabel, defaultValue, choiceValues){ + var labelElement; + if(choiceValues){ + var fieldElement = new qx.ui.form.SelectBox(); + for(var key in choiceValues){ + fieldElement.add(new qx.ui.form.ListItem(choiceValues[key], null, key)); + } + }else{ + var fieldElement = new qx.ui.form.TextField(); + } + if(defaultValue){ + fieldElement.setValue(defaultValue); + } + if(fieldName && fieldLabel){ + labelElement = new qx.ui.basic.Label(fieldLabel); + formObject.fields[fieldName] = fieldElement; + }else{ + labelElement = new qx.ui.form.TextField(); + formObject.freeFields.push({ + labelEl:labelElement, + valueEl:fieldElement + }); + } + this._addFormEntry(formObject, labelElement, fieldElement); + }, + + /** + * Add an header + * @param formObject {Map} The form part + * @param content {Mixed} Content to add. + * @param additionnalButton {Mixed} Any widget to add on the east. + */ + _addFormHeader : function(formObject, content, additionnalButton){ + var header = new qx.ui.basic.Label(''+content+''); + header.setRich(true); + if(!additionnalButton){ + header.setPaddingTop(10); + formObject.pane.add(header); + }else{ + var pane = new qx.ui.container.Composite(new qx.ui.layout.Dock()); + pane.setPaddingTop(10); + pane.setPaddingRight(10); + pane.add(header, {edge:'center'}); + pane.add(additionnalButton, {edge:'east'}); + formObject.pane.add(pane); + } + }, + + /** + * Adds a label/input like entry in the form. + * @param formObject {Map} The form part + * @param labelElement {Object} Either a label or an input + * @param fieldElement {Object} Any form input. + */ + _addFormEntry : function(formObject, labelElement, fieldElement){ + var entryPane = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)); + labelElement.setWidth(100); + labelElement.setTextAlign("right"); + entryPane.add(labelElement); + entryPane.add(new qx.ui.basic.Label(':')); + fieldElement.setWidth(150); + entryPane.add(fieldElement); + formObject.pane.add(entryPane); + }, + + /* + _refreshTopicsSubscriptions : function(changeTopicsEvent){ + var oldTopics = changeTopicsEvent.getOldData() || {}; + var newTopics = changeTopicsEvent.getData(); + var removed = []; + var added = []; + for(var key in oldTopics){ + if(!newTopics[key]) { + //this._removeAmqListener(key); + } + } + for(var key in newTopics){ + if(!oldTopics[key]) { + //this._addAmqListener(key); + } + } + }, + */ + + /** + * Refresh the selector when the topics are updated. + * @param changeTopicsEvent {qx.event.type.DataEvent} The reload event. + */ + _feedSelector : function(changeTopicsEvent){ + var topics = changeTopicsEvent.getData(); + this.agentSelector.removeAll(); + var emptyItem = new qx.ui.form.ListItem("", null, ""); + this.agentSelector.add(emptyItem); + this.agentSelector.setSelected(emptyItem); + for(var key in topics){ + var listItem = new qx.ui.form.ListItem(topics[key], null, key); + this.agentSelector.add(listItem); + } + }, + + /* + _addAmqListener: function(uuid){ + this._amqClient.addListener("slcExec", "topic://agent."+uuid+".newExecution", function(response){ + var message = org.argeo.ria.util.Element.selectSingleNode(response, "slc:slc-execution"); + var slcExec = new org.argeo.slc.ria.SlcExecutionMessage(message.getAttribute("uuid")); + slcExec.fromXml(message); + this.logModel.addRows([ + [new Date().toString(), slcExec.getHost()+' ('+slcExec.getUuid()+')', slcExec.getStatus()] + ]); + }, this); + }, + + _removeAmqListener : function(uuid){ + this._amqClient.removeListener("slcExec", "topic://agent."+uuid+".newExecution"); + }, + */ + + /** + * Make an SlcExecutionMessage from the currently displayed form. + * @param crtPartId {String} The form part currently displayed + * @param slcExec {org.argeo.slc.ria.SlcExecutionMessage} The message to fill. + * @param fields {Map} The fields of the form + * @param hiddenFields {Map} The hidden ones + * @param freeFields {Array} The free fields. + */ + _prepareSlcExecutionMessage : function(crtPartId, slcExec, fields, hiddenFields, freeFields){ + if(crtPartId == "standard"){ + slcExec.setStatus(fields.status.getValue()); + slcExec.setHost(fields.host.getValue()); + slcExec.setUser(fields.user.getValue()); + }else{ + slcExec.addAttribute("ant.file", fields["ant.file"].getValue()); + } + for(var i=0;i the selected test" + (sel.length>1?"s":"") + " from the Batch?"); + modal.addListener("ok", function(){ + for(var i=0;i 0)) this.setEnabled(true); + }, + command : null + }, + "reloadagents" : { + label : "Reload Agents", + icon : "resource/slc/view-refresh.png", + shortcut : "Control+r", + enabled : true, + menu : "Launcher", + toolbar : "launcher", + callback : function(e){ + var req = org.argeo.slc.ria.SlcApi.getListAgentsService("agents"); + req.send(); + }, + command : null + }, + "reloadtree" : { + label : "Reload", + icon : "resource/slc/view-refresh.png", + shortcut : "Control+m", + enabled : false, + menu : "Launcher", + toolbar : "launcher", + callback : function(e){ + var selected = this.tree.getSelectedItem(); + if(selected.classname == "org.argeo.ria.components.DynamicTreeFolder"){ + if(selected.getUserData("moduleData")){ + // It's a "module" node, first trigger the reloadBundle.service + selected.setUserData("dataModel", {}); + selected.setEnabled(false); + selected.setOpen(false); + var moduleData = selected.getUserData("moduleData"); + var bundleService = org.argeo.slc.ria.SlcApi.getReloadBundleService(moduleData.name, moduleData.version); + bundleService.addListener("completed", function(response){ + selected.setEnabled(true); + selected.setOpen(true); + selected.reload(); + }, this); + //bundleService.send(); + //Do not send, not implemented yet, false timer instead. + qx.event.Timer.once(function(response){ + selected.setEnabled(true); + selected.setOpen(true); + selected.reload(); + }, this, 2000); + }else{ + selected.reload(); + } + } + }, + selectionChange : function(viewId, selection){ + if(viewId != "form:tree") return; + if(!selection || selection.length != 1) return; + var item = selection[0]; + if(!qx.Class.isSubClassOf(qx.Class.getByName(item.classname), qx.ui.tree.AbstractTreeItem)) return; + this.setEnabled(false); + if(qx.Class.isSubClassOf(qx.Class.getByName(item.classname), org.argeo.ria.components.DynamicTreeFolder)){ + this.setEnabled(true); + } + }, + command : null + } + } + }, + /** + * A map containing all currently registered agents. + */ + registeredTopics : { + init : {}, + check : "Map", + event : "changeRegisteredTopics" + } + }, + + statics : { + /** + * Loader for the "flow" level : takes a folder containing "moduleData" and create its children. + * @param folder {qx.ui.tree.TreeFolder} A Tree folder containing in the key "moduleData" of its user data a map containing the keys {name,version} + */ + flowLoader : function(folder){ + var moduleData = folder.getUserData("moduleData"); + //var pathStub = ["", "/test/toto/zobi", "loop"]; + //var indexStub = 0; + + var req = org.argeo.slc.ria.SlcApi.getLoadExecutionDescriptorService(moduleData.name, moduleData.version); + req.addListener("completed", function(response){ + var executionModule = new org.argeo.slc.ria.execution.Module(); + executionModule.setXmlNode(response.getContent()); + var execFlows = executionModule.getExecutionFlows(); + for(var key in execFlows){ + var file = new qx.ui.tree.TreeFile(key); + var path = execFlows[key].getPath(); + //path = pathStub[indexStub]; + //indexStub ++; + file.setUserData("executionModule", executionModule); + file.setUserData("executionFlow", execFlows[key]); + org.argeo.slc.ria.NewLauncherApplet.attachNodeByPath(folder, path, file); + folder.appendDragData(file); + } + folder.setLoaded(true); + }); + req.send(); + }, + + /** + * Loader for the "modules" level : takes any tree folder, currently the root folder. + * @param folder {qx.ui.tree.TreeFolder} The root folder + */ + modulesLoader : function(folder){ + var req = org.argeo.slc.ria.SlcApi.getListModulesService(); + req.addListener("completed", function(response){ + var descriptors = org.argeo.ria.util.Element.selectNodes(response.getContent(), "slc:object-list/slc:execution-module-descriptor"); + var mods = {}; + for(var i=0;i'); + builder.add(''+this.getStatus()+''); + builder.add(''+this.getType()+''); + builder.add(''+this.getHost()+''); + builder.add(''+this.getUser()+''); + var attr = this.getAttributes(); + if(qx.lang.Object.getLength(attr)){ + builder.add(''); + for(var key in attr){ + builder.add(''+attr[key]+''); + } + builder.add(''); + } + builder.add(''); + return builder.get(); + }, + + /** + * Parse an XML answer and fill the object with it. + * @param slcExecXml {String} An slcExecMessage mapped in XML. + */ + fromXml : function(slcExecXml){ + var NSMap = {slc:"http://argeo.org/projects/slc/schemas"}; + this.setStatus(org.argeo.ria.util.Element.getSingleNodeText(slcExecXml, "slc:status", NSMap)); + this.setType(org.argeo.ria.util.Element.getSingleNodeText(slcExecXml, "slc:type", NSMap)); + this.setHost(org.argeo.ria.util.Element.getSingleNodeText(slcExecXml, "slc:host", NSMap)); + this.setUser(org.argeo.ria.util.Element.getSingleNodeText(slcExecXml, "slc:user", NSMap)); + var attributes = org.argeo.ria.util.Element.selectNodes(slcExecXml, "slc:attribute", NSMap); + for(var i=0;i'+valuesXml+''; + + var execSpecDescXML = this.getOriginalSpec().toXml(); + + var moduleData = ''+this.getModule().getName()+''+this.getModule().getVersion()+''; + + return ''+moduleData + execFlowDescXML + execSpecDescXML +''; + + }, + + /** + * Fetch the Spec Values with the Flow Values to make the current instance value + */ + fetchInstanceValues : function(){ + var specValues = this.getOriginalSpec().getValues(); + var flow = this.getFlow(); + var instanceValues = {}; + for(var key in specValues){ + var flowValue = flow.getValue( + key, + specValues[key].getSpecType(), + specValues[key].getSpecSubType() + ); + var instValue = specValues[key].clone(); + if(flowValue){ + instValue.setValue(flowValue); + } + instanceValues[key] = instValue; + } + this.setValues(instanceValues); + //this.debug(instanceValues); + } + } +}); \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/Flow.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/Flow.js new file mode 100644 index 000000000..017599ee6 --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/Flow.js @@ -0,0 +1,104 @@ +/** + * Wrapper for ExecutionFlow server object + */ +qx.Class.define("org.argeo.slc.ria.execution.Flow", { + + extend : qx.core.Object, + + properties : { + /** + * Name of this Execution Flow + */ + name : { + check : "String", + init : "" + }, + /** + * An optional path describing this flow + */ + path : { + check : "String", + nullable : true + }, + /** + * Name of the associated spec, to be found in the module + */ + executionSpecName : { + check : "String" + }, + /** + * Reference the actual ExecutionSpec object + */ + executionSpec : { + check : "org.argeo.slc.ria.execution.Spec" + }, + /** + * The values to init the ExecutionSpec + */ + values : { + check : "Node" + }, + /** + * Castor representation of the object + */ + xmlNode : { + apply : "_applyXmlNode" + } + }, + + statics : { + /** + * Xpath to the name + */ + XPATH_NAME : "@name", + /** + * XPath to the ExecutionSpec name + */ + XPATH_EXEC_SPEC_NAME : "@executionSpec", + /** + * XPath to the values + */ + XPATH_VALUES : "slc:values", + /** + * An optional hierarchical path + */ + XPATH_PATH : "@path" + }, + + construct : function(){ + this.base(arguments); + }, + + members : { + /** + * Init the object from an XML representation + * @param xmlNode {Node} Castor representation of this object + */ + _applyXmlNode : function(xmlNode){ + this.set({ + name : org.argeo.ria.util.Element.getSingleNodeText(xmlNode, this.self(arguments).XPATH_NAME), + path : org.argeo.ria.util.Element.getSingleNodeText(xmlNode, this.self(arguments).XPATH_PATH), + executionSpecName : org.argeo.ria.util.Element.getSingleNodeText(xmlNode, this.self(arguments).XPATH_EXEC_SPEC_NAME) + }); + var values = org.argeo.ria.util.Element.selectNodes(xmlNode, this.self(arguments).XPATH_VALUES); + this.setValues(values[0]); + }, + /** + * Get a given value inside the values map + * @param key {String} The key of the value + * @param specType {String} Expected type (currently "primitive" and "ref" are supported) + * @param specSubType {String} Expected subtype (depends on the type) + * @return {String} Value if it is set. + */ + getValue: function(key, specType, specSubType){ + var xpath; + if(specType == "primitive"){ + xpath = 'slc:value[@key="'+key+'"]/slc:primitive-value[@type="'+specSubType+'"]'; + }else if(specType == "ref"){ + xpath = 'slc:value[@key="'+key+'"]/slc:ref-value/slc:label'; + } + return org.argeo.ria.util.Element.getSingleNodeText(this.getValues(), xpath); + } + } + +}); \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/Message.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/Message.js new file mode 100644 index 000000000..0140311db --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/Message.js @@ -0,0 +1,148 @@ +/** + * A generic JMS slcExecution message encapsulator. + */ +qx.Class.define("org.argeo.slc.ria.execution.Message", { + extend : qx.core.Object, + /** + * New instance + * @param uuid {String} The Uuid of the message. If none is passed, one is generated. + */ + construct : function(uuid){ + this.base(arguments); + if(uuid){ + this.setUuid(uuid); + }else{ + var s = []; + var itoh = '0123456789ABCDEF'; + for (var i = 0; i <36; i++) s[i] = Math.floor(Math.random()*0x10); + s[14] = 4; // Set 4 high bits of time_high field to version + s[19] = (s[19] & 0x3) | 0x8; // Specify 2 high bits of clock sequence + for (var i = 0; i <36; i++) s[i] = itoh[s[i]]; + s[8] = s[13] = s[18] = s[23] = '-'; + this.setUuid(s.join('').toLowerCase()); + } + this.setBatchEntrySpecs([]); + this.setAttributes({}); + }, + properties : { + /** + * The unique id identifying the message + */ + uuid : { + check : "String" + }, + /** + * Execution status + */ + status : { + check : "String", + init : "STARTED" + }, + /** + * Execution type + */ + type : { + check : "String", + init : "slcAnt" + }, + /** + * Execution Host + */ + host : { + check : "String", + init : "localhost" + }, + /** + * Execution User + */ + user : { + check : "String", + init : "user" + }, + /** + * Date of the message. now() by default. + */ + date : { + check : "String", + init : new Date().toString() + }, + /** + * Additionnal attributes as map of key/values + */ + attributes : { + check : "Map" + }, + batchEntrySpecs : { + check : "Array" + } + }, + members : { + + /** + * Add a free attribute to the message + * @param attName {String} Name + * @param attValue {String} Value + */ + addAttribute: function(attName, attValue){ + var attr = this.getAttributes(); + attr[attName] = attValue; + this.setAttributes(attr); + }, + + addBatchEntrySpec : function(entrySpec){ + this.getBatchEntrySpecs().push(entrySpec); + }, + + /** + * Build the xml formatted message body to send + * + * @return {String} The message content as Xml + */ + toXml : function (){ + var builder = new qx.util.StringBuilder(); + builder.add(''); + builder.add(''+this.getStatus()+''); + builder.add(''+this.getType()+''); + builder.add(''+this.getHost()+''); + builder.add(''+this.getUser()+''); + var flows = this.getBatchEntrySpecs(); + if(flows.length){ + builder.add(''); + for(var i=0;i'); + } + var attr = this.getAttributes(); + if(qx.lang.Object.getLength(attr)){ + builder.add(''); + for(var key in attr){ + builder.add(''+attr[key]+''); + } + builder.add(''); + } + builder.add(''); + return builder.get(); + }, + + /** + * Parse an XML answer and fill the object with it. + * @param slcExecXml {String} An slcExecMessage mapped in XML. + */ + fromXml : function(slcExecXml){ + var NSMap = {slc:"http://argeo.org/projects/slc/schemas"}; + this.setStatus(org.argeo.ria.util.Element.getSingleNodeText(slcExecXml, "slc:status", NSMap)); + this.setType(org.argeo.ria.util.Element.getSingleNodeText(slcExecXml, "slc:type", NSMap)); + this.setHost(org.argeo.ria.util.Element.getSingleNodeText(slcExecXml, "slc:host", NSMap)); + this.setUser(org.argeo.ria.util.Element.getSingleNodeText(slcExecXml, "slc:user", NSMap)); + var attributes = org.argeo.ria.util.Element.selectNodes(slcExecXml, "slc:attribute", NSMap); + for(var i=0;i'+valuesXml+''; + } + } + +}); \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/SpecEditor.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/SpecEditor.js new file mode 100644 index 000000000..6d8683989 --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/SpecEditor.js @@ -0,0 +1,254 @@ +/** + * Generic modal popup window. + * It is layed out with a dock layout. When adding components to it, they are added as "center". + * @author Charles du Jeu + */ +qx.Class.define("org.argeo.slc.ria.execution.SpecEditor", +{ + extend : qx.ui.window.Window, + + properties : { + /** + * The Spec to edit + */ + batchEntrySpec : { + check : "org.argeo.slc.ria.execution.BatchEntrySpec" + } + }, + + events : { + /** + * Triggered when the user clicks the "save" button. + */ + "save" : "qx.event.type.Event", + /** + * Triggered when any data is modified + */ + "modified" : "qx.event.type.Event" + + }, + /** + * Opens an editor with the given values. + * @param batchEntrySpec {org.argeo.slc.ria.execution.BatchEntrySpec} The initial spec to edit + */ + construct : function(batchEntrySpec){ + var editorLabel = "Edit Specs for "+batchEntrySpec.getLabel(); + this.base(arguments, editorLabel); + this.set({ + batchEntrySpec : batchEntrySpec, + showMaximize : false, + showMinimize : false, + width: Math.min(parseInt(qx.bom.Viewport.getWidth()*90/100), 400), + height: parseInt(qx.bom.Viewport.getHeight()*60/100) + }); + this.setLayout(new qx.ui.layout.Dock()); + this.setModal(true); + this.center(); + this._initFormObject(this.getBatchEntrySpec().getLabel()); + this._addFormHeader(this.formObject, editorLabel); + this.createFormFromSpec(); + this.addContent(this.formObject.pane); + this.addOkCancel(); + this.addListener("save", function(e){ + this.saveFormToSpec(); + }, this); + }, + + members : { + /** + * Builds the form from the BatchEntrySpec + */ + createFormFromSpec : function(){ + var values = this.getBatchEntrySpec().getValues(); + for(var key in values){ + var valueObj = values[key]; + var label = key; + var hidden = valueObj.getHidden(); + var disabled = valueObj.getFrozen(); + var value = valueObj.getValue(); + var type = valueObj.getSpecType(); + var subType = valueObj.getSpecSubType(); + if(type == "primitive" && !hidden){ + this._addFormInputText(this.formObject, key, key, value, disabled, subType); + } + } + }, + /** + * Gather data from the form + */ + saveFormToSpec : function(){ + var values = this.getBatchEntrySpec().getValues(); + for(var key in values){ + var valueObj = values[key]; + var hidden = valueObj.getHidden(); + var disabled = valueObj.getFrozen(); + if(valueObj.getSpecType() == "primitive"){ + if(!hidden && !disabled){ + valueObj.setValue(this.formObject.fields[key].getValue()); + } + } + } + }, + + /** + * Display a component (panel) in the center of the popup + * @param panel {qx.ui.core.Widget} A gui component (will be set at width 100%). + */ + addContent: function(panel){ + this.add(new qx.ui.container.Scroll(panel), {edge:'center', width:'100%'}); + }, + /** + * Automatically attach to the application root, then show. + */ + attachAndShow:function(){ + org.argeo.ria.components.ViewsManager.getInstance().getApplicationRoot().add(this); + this.show(); + }, + /** + * Init a form part : creates a pane, a set of fields, etc. + * @param label {String} A label + * @return {Map} The form part. + */ + _initFormObject : function(label){ + this.formObject = {}; + this.formObject.hiddenFields = {}; + this.formObject.freeFields = []; + this.formObject.fields = {}; + this.formObject.label = label; + this.formObject.pane = new qx.ui.container.Composite(new qx.ui.layout.VBox(5)); + return this.formObject; + }, + + /** + * Creates a simple label/input form entry. + * @param formObject {Map} The form part + * @param fieldName {String} Name + * @param fieldLabel {String} Label of the field + * @param defaultValue {String} The default value + * @param choiceValues {Map} An map of values + * @param disabled {Boolean} The field is not writable + * @param subType {String} The type expected (string, integer, etc). + */ + _addFormInputText : function(formObject, fieldName, fieldLabel, defaultValue, disabled, subType, choiceValues){ + var labelElement; + if(choiceValues){ + var fieldElement = new qx.ui.form.SelectBox(); + for(var key in choiceValues){ + fieldElement.add(new qx.ui.form.ListItem(choiceValues[key], null, key)); + } + fieldElement.addListener("changeSelected", function(e){this.fireEvent("modified")}, this); + }else{ + var fieldElement = new qx.ui.form.TextField(); + if(subType == "integer"){ + fieldElement.addListener("changeValue", function(e){ + var isNum = !isNaN(e.getData() * 1); + if(!isNum){ + alert("Warning, this field only accepts Integers!"); + } + }, this); + } + fieldElement.addListener("input", function(e){this.fireEvent("modified")}, this); + } + if(defaultValue){ + fieldElement.setValue(defaultValue); + } + if(fieldName && fieldLabel){ + labelElement = new qx.ui.basic.Label(fieldLabel); + formObject.fields[fieldName] = fieldElement; + }else{ + labelElement = new qx.ui.form.TextField(); + formObject.freeFields.push({ + labelEl:labelElement, + valueEl:fieldElement + }); + } + if(disabled) fieldElement.setEnabled(false); + this._addFormEntry(formObject, labelElement, fieldElement); + }, + + /** + * Add an header + * @param formObject {Map} The form part + * @param content {Mixed} Content to add. + * @param additionnalButton {Mixed} Any widget to add on the east. + */ + _addFormHeader : function(formObject, content, additionnalButton){ + var header = new qx.ui.basic.Label(''+content+''); + header.setRich(true); + if(!additionnalButton){ + header.setPaddingBottom(10); + formObject.pane.add(header); + }else{ + var pane = new qx.ui.container.Composite(new qx.ui.layout.Dock()); + pane.setPaddingBottom(10); + pane.setPaddingRight(10); + pane.add(header, {edge:'center'}); + pane.add(additionnalButton, {edge:'east'}); + formObject.pane.add(pane); + } + }, + + /** + * Adds a label/input like entry in the form. + * @param formObject {Map} The form part + * @param labelElement {Object} Either a label or an input + * @param fieldElement {Object} Any form input. + */ + _addFormEntry : function(formObject, labelElement, fieldElement){ + var entryPane = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)); + labelElement.setWidth(150); + labelElement.setTextAlign("right"); + entryPane.add(labelElement); + entryPane.add(new qx.ui.basic.Label(':')); + fieldElement.setWidth(150); + entryPane.add(fieldElement); + formObject.pane.add(entryPane); + }, + + /** + * Adds a close button bottom-center aligned to the popup + */ + addCloseButton : function(){ + this.closeButton = new qx.ui.form.Button("Close"); + this.closeButton.addListener("execute", this._closeAndDestroy, this); + this.add(this.closeButton, {edge:'south'}); + }, + /** + * Adds two buttons bottom-center aligned (Ok and Cancel). + * Ok button has no listener by default, Cancel will close and destroy the popup. + */ + addOkCancel : function(){ + var buttonPane = new qx.ui.container.Composite(new qx.ui.layout.HBox(5, 'right')); + buttonPane.setAlignX("center"); + this.add(buttonPane, {edge:"south"}); + this.okButton = new qx.ui.form.Button("Save"); + this.okButton.setEnabled(false); + this.addListener("modified", function(e){ + this.okButton.setEnabled(true); + }, this); + this.okButton.addListener("execute", function(e){ + this.fireEvent("save"); + this.okButton.setEnabled(false); + }, this); + this.cancelButton = new qx.ui.form.Button("Close"); + this.cancelButton.addListener("execute", this._closeAndDestroy, this); + + this.saveCloseButton = new qx.ui.form.Button("Save & Close"); + this.saveCloseButton.addListener("execute", function(e){ + this.fireEvent("save"); + this._closeAndDestroy(); + }, this); + + buttonPane.add(this.okButton); + buttonPane.add(this.cancelButton); + buttonPane.add(this.saveCloseButton); + }, + /** + * Close this modal window and destroy it. + */ + _closeAndDestroy : function(){ + this.hide(); + this.destroy(); + } + } +}); \ No newline at end of file diff --git a/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/Value.js b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/Value.js new file mode 100644 index 000000000..b5944a019 --- /dev/null +++ b/server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/execution/Value.js @@ -0,0 +1,129 @@ +/** + * Wrapper for SlcValue object + */ +qx.Class.define("org.argeo.slc.ria.execution.Value", { + + extend : qx.core.Object, + + properties : { + /** + * Name of this Execution Flow + */ + key : { + check : "String", + init : "" + }, + /** + * The type of this value, for the moment "primitive" and "ref" are supported + */ + specType : { + check : "String", + init : "" + }, + /** + * Subtype, depending on the "type". + */ + specSubType : { + check : "String" + }, + /** + * Whether it is a parameter or not + */ + parameter : { + check : "Boolean" + }, + /** + * Whether it is frozen on the server, i.e. disabled in the form + */ + frozen : { + check : "Boolean" + }, + /** + * Should not be editable nor seeable, thus hidden + */ + hidden : { + check : "Boolean" + }, + /** + * The real value + */ + value : { + nullable : true + }, + /** + * Castor representation of the object + */ + xmlSpecNode : { + apply : "_applyXmlSpecNode" + } + }, + + statics : { + XPATH_KEY : "@key" + }, + + construct : function(){ + this.base(arguments); + }, + + members : { + /** + * Init the object from an XML representation + * @param xmlNode {Node} Castor representation of this object + */ + _applyXmlSpecNode : function(xmlNode){ + this.setKey(org.argeo.ria.util.Element.getSingleNodeText(xmlNode, "@key")); + var childs = xmlNode.childNodes; + for(var i=0;i