Team:Team:Freiburg software/Code/qooxdoo/Application.js

background-position:0% -42px; } background-position:100% -42px; color:#213340; } display:none; }
 * 1) tabs a.code_active {
 * 1) tabs a.code_active span {
 * 1) toc {

/* ************************************************************************

Copyright: SynBioWave (synbiowave.org)

License: GPL

Authors: David Nellessen (mail@davidn.de) DESCRIPTION: This Application is used to create a GUI inside a wave gadget from a JSON passed via the wave API (wave.getState). This Application expects the JSON data to construct the menu from in wave.getState('ui.structure') with a special structure we call the qooxwave protocol. This protocol is not yet completed. For understanding qooxwave protocol, have a look at the documentation: http://2009.igem.org/Team:Freiburg_software/Project/qooxWave-details TODO: - complete qooxwave protocol - gadget resizing should respect menus - Refreshing UI on every state update is not neccessary - solve absolute url problem (still pointing to sourceforge.net in config.josn) - rebuild the model on user input and bind model to store - MVC improvement: when changing something like clicking on a checkbox, the model is not updated correctly therefore the state has still the old value (no checkbox clicked), nothing will happen, eventhough the server might whant to uncheck the checkbox! So there must be either - a update of the model - allways update gui on stateupdate - some kind of mixing of the above: not on every state update, but if the model might be out of sync - modelling is very sensible cerncerning their ids. they cannot contain certain characters, which? - check target url for upload widget



/* ************************************************************************


 * 1) asset(qooxwaveclient/*)



/** * This is the main application class of "qooxwaveClient" */ qx.Class.define("qooxwaveclient.Application", { extend : qx.application.Standalone,

properties : { //this app makes use of the dynamic property feature of qooxdoo. guiModel bind to the model in the store using data binding feature of qooxdoo guiModel : {nullable : true, apply : "_applyGuiModel", event : "changeGuiModel"} },

/* *****************************************************************************     MEMBERS ***************************************************************************** */

members : {   /**     * This method contains the initial application code and gets called * during startup of the application */   main : function {     // Call super class this.base(arguments);

// Enable logging in debug variant if (qx.core.Variant.isSet("qx.debug", "on")) {       // support native logging capabilities, e.g. Firebug for Firefox qx.log.appender.Native; // support additional cross-browser console. Press F7 to toggle visibility qx.log.appender.Console; }

/*     -        Below is actual application code... -     */      /*       * Define main objects */     //general member variables: this.namespace = new Object; this.namespace.ui = 'ui'; this.namespace.ui_structure = this.namespace.ui + '.structure'; //set minHeight of the gadget. This is unfortunaltely nedded, because the auto resizing does not respect menus this.minHeight = 80; //Get Wave Object (simulated when outside of wave) var wave = new qooxwaveclient.wave.WaveFactory.getWave; //create a Store for server-client (wave-thisApp) communication this.store = new qooxwaveclient.Store(wave, new Array(this.namespace.ui_structure), this.namespace.ui_structure); wave.setStateCallback(this.store.processStateUpdate, this.store); this.store.bind("model", this, "guiModel");

//uncomment the following lines to activate the testing ui     //this.buildTestingUI; //this.minHeight = 400; //Testing Ui can also be activated with a shortcut (works only outside wave) var find = new qx.event.Command("Control-Y"); find.addListener("execute", function{   	  if(qx.ui.core.Widget.contains(this.getRoot, this.testUi)){    		  this.testUi.destroy;    		  this.minHeight = 100;    	  }    	  else{    		  this.buildTestingUI;    		  this.minHeight = 400;    	  }    	  this.refresh;      }, this); },   //build the main Widget from guiModel | destruction suggested first buildMainWidget : function (model){ this.__buildRootGadget; if(!model) return true; if(model.type == "ui" && model.subitem){ //distinguish different implementations of qooxwave model = model.subitem; }	     for(var itemid in model){ var widget = this.__loop(itemid, model[itemid]); if(widget.qxwidget) this.gadget.add(widget.qxwidget); else return false; }	     return true; },   //public method to destruct gadget destructMainWidget :function { this.__destructRootGadget; },	//reBuild this.gadget from guiModel refresh : function { this.destructMainWidget; //alert(this.getGuiModel.toString); this.buildMainWidget(this.getGuiModel); this.resizeGadget; return true; },	//resize wave gadget resizeGadget : function { var heightDest = this.minHeight; //minimal height if(this.gadget.getBounds)	var heightDest = Math.max(heightDest, this.gadget.getBounds.height); if(typeof gadgets != "undefined") gadgets.window.adjustHeight(heightDest); this.debug("SET HEIGHT: " + heightDest); },	//executed when new value of GuiModel applied _applyGuiModel : function (value, old){ if(value == old) this.debug("Apply guiModel. But NO Change detected"); else { this.debug("Apply guiModel: " + value); this.refresh; }	},	//loops an object item according to the qooxWave protocol __loop : function (itemid, item){ item.id = itemid; if(item.type == "toolbar") item = this.__processToolbar(itemid, item); else if(item.type == "button") item = this.__processButton(itemid, item); else if(item.type == "checkbox") item = this.__processCheckbox(itemid, item); else if(item.type == "menu") item = this.__processMenu(itemid, item); else if(item.type == "label") item = this.__processLabel(itemid, item); else if(item.type == "form") item = this.__processForm(itemid, item); else if(item.type == "upload") item = this.__processUpload(itemid, item); else if(item.type == "chron") item = this.__processChron(itemid, item); return item; },

//proccesses the toolbar typed items __processToolbar : function (itemid, item){ if(typeof item.qxwidget == "undefined") item.qxwidget = new qx.ui.toolbar.ToolBar; //could be create earlier if(typeof item.subitem != "undefined"){ //loop subitems for(var subitemid in item.subitem){ if(item.subitem[subitemid].type == "button"){ //if type of subitem is button create a special toolbar button (design issue) item.subitem[subitemid].qxwidget = new qx.ui.toolbar.Button; item.subitem[subitemid] = this.__loop(subitemid, item.subitem[subitemid]); item.qxwidget.add(item.subitem[subitemid].qxwidget); }				else if(item.subitem[subitemid].type == "checkbox"){ //if type of subitem is checkbox, create a special toolbar button (design issue) item.subitem[subitemid].qxwidget = new qx.ui.toolbar.CheckBox; item.subitem[subitemid] = this.__loop(subitemid, item.subitem[subitemid]); item.qxwidget.add(item.subitem[subitemid].qxwidget); }				else if(item.subitem[subitemid].type == "menu"){ //create a special menu (design issue) item.subitem[subitemid].qxwidget = new qx.ui.toolbar.MenuButton; item.subitem[subitemid] = this.__loop(subitemid, item.subitem[subitemid]); item.qxwidget.add(item.subitem[subitemid].qxwidget); }			}		}		return item; },	//processes the form typed items __processForm : function (itemid, item){ if(typeof item.qxform == "undefined") item.qxform = new qx.ui.form.Form; //could be create earlier	} item.qxform.addGroupHeader(item.label);

//create widget item.qxwidget = new qx.ui.groupbox.GroupBox(""+item.label, null); item.qxwidget.setLayout(new qx.ui.layout.VBox(5)); item.qxwidget.setMaxWidth(300); //A atom that shows loading state var loadingAtom = new qx.ui.basic.Atom("State", "qooxwaveclient/ajax-loader-large.gif"); loadingAtom.set({alignX : "center", marginTop : 10}); loadingAtom.hide; //create model var model = new Object; //create submit queue var queue = new Array; var queueCount = 0; if(typeof item.subitem != "undefined"){ //loop subitems | most of them are processed directly here, cause they can only be subitems of form for(var subitemid in item.subitem){ var skipModelSetup = false; if(item.subitem[subitemid].type == "textarea"){ item.subitem[subitemid].qxwidget = new qx.ui.form.TextArea; item.subitem[subitemid].value = item.subitem[subitemid].value+""; }				else if(item.subitem[subitemid].type == "textfield"){ item.subitem[subitemid].qxwidget = new qx.ui.form.TextField; item.subitem[subitemid].qxwidget.setMinWidth(150); item.subitem[subitemid].value = item.subitem[subitemid].value+""; }				else if(item.subitem[subitemid].type == "checkbox"){ item.subitem[subitemid].qxwidget = new qx.ui.form.CheckBox; item.subitem[subitemid].value = !!item.subitem[subitemid].value; //parse to boolean }				else if(item.subitem[subitemid].type == "radio"){ item.subitem[subitemid].qxwidget = new qx.ui.form.RadioButton; item.subitem[subitemid].value = !!item.subitem[subitemid].value; //parse to boolean //add to radio group if(!item.subitem[subitemid].group) continue; if(typeof item.radiogroups == "undefined") item.radiogroups = new Object; if(typeof item.radiogroups[item.subitem[subitemid].group] == "undefined") item.radiogroups[item.subitem[subitemid].group] = new qx.ui.form.RadioButtonGroup; item.radiogroups[item.subitem[subitemid].group].add(item.subitem[subitemid].qxwidget); }				else if(item.subitem[subitemid].type == "download"){ //section copied from == "upload" so the notaion is wrong. TODO: change this item.subitem[subitemid].upload = new qooxwaveclient.Download(item.subitem[subitemid].target+"", this.namespace.ui + "." + subitemid, this.store, false, "application/x-www-form-urlencoded"); item.qxwidget.add(item.subitem[subitemid].upload); item.subitem[subitemid].qxwidget = new qx.ui.form.TextField; item.subitem[subitemid].qxwidget.setReadOnly(true); //bind filename upload -> textfield item.subitem[subitemid].upload.bind("fileName", item.subitem[subitemid].qxwidget, "value"); item.subitem[subitemid].value = item.subitem[subitemid].value+"";

//process submitting item.subitem[subitemid].upload.queueCount = queueCount; item.subitem[subitemid].upload.go = function{ toogelLoadingAtom("downloading ..."); this.modefieUri(item.serialize("uri")); this.submit; toogelLoadingAtom("Uploading " + this.getFileName + "..."); };					item.subitem[subitemid].upload.addListener("onload", function(e){						qx.event.Timer.once(queue[this.queueCount+1].go, queue[this.queueCount+1], 1000);					},item.subitem[subitemid].upload); queue[queueCount] = item.subitem[subitemid].upload; queueCount++; //hide textfield item.subitem[subitemid].qxwidget.setEnabled(false); }				else if(item.subitem[subitemid].type == "upload" ){ item.subitem[subitemid].upload = new qooxwaveclient.Upload(item.subitem[subitemid].target+"", this.namespace.ui + "." + subitemid, this.store, false, "multipart/form-data"); item.qxwidget.add(item.subitem[subitemid].upload); item.subitem[subitemid].qxwidget = new qx.ui.form.TextField; item.subitem[subitemid].qxwidget.setReadOnly(true); //bind filename upload -> textfield item.subitem[subitemid].upload.bind("fileName", item.subitem[subitemid].qxwidget, "value"); item.subitem[subitemid].value = item.subitem[subitemid].value+"";

//process submitting item.subitem[subitemid].upload.queueCount = queueCount; item.subitem[subitemid].upload.go = function{ toogelLoadingAtom("Uploading ..."); this.modefieUri(item.serialize("uri")); this.submit; toogelLoadingAtom("Uploading " + this.getFileName + "..."); };					item.subitem[subitemid].upload.addListener("onload", function(e){						qx.event.Timer.once(queue[this.queueCount+1].go, queue[this.queueCount+1], 1000);					},item.subitem[subitemid].upload); item.subitem[subitemid].upload.addListener("error", function(e){						alert('There was one upload field not specified. Nothing to send.');						qx.event.Timer.once(queue[this.queueCount+1].go, queue[this.queueCount+1], 1000);					},item.subitem[subitemid].upload); queue[queueCount] = item.subitem[subitemid].upload; queueCount++; //hide textfield item.subitem[subitemid].qxwidget.setEnabled(false); }				else continue; //make sure only available subitems are processed if(!skipModelSetup){ //TODO ... HMMMM model[subitemid] = item.subitem[subitemid].value; //fill the model item.subitem[subitemid].qxwidget.setValue(item.subitem[subitemid].value); }				item.subitem[subitemid].qxwidget.setWidth(180); //TODO item.qxform.add(item.subitem[subitemid].qxwidget, item.subitem[subitemid].label, null, subitemid); }		}		//form model and data binding model = qx.data.marshal.Json.createModel(model); var formController = new qx.data.controller.Form(model, item.qxform); item.serialize = function(method){ if(method == "json"){ var modelJson = qx.util.Serializer.toJson(model); var value = modelJson+""; value = value.replace(/"/g, "'");	   	}	    	else if(method == "uri"){	    		var modelUri = qx.util.Serializer.toUriParameter(model, function(object){return ""+object;});	    		var value = modelUri+"";		    	value = value.replace(/"/g, "'"); }	   	else value = null; return value; };	   //toggle loading icon toogelLoadingAtom = function (label){ //if(qx.ui.core.contains(item.qxwidget, this.)) if(!label) loadingAtom.hide; else { loadingAtom.setLabel(""+label); loadingAtom.show; }	   };		// send button var sendButton = new qx.ui.form.Button("Send", "icon/16/actions/dialog-ok.png"); queue[queueCount] = new Object; queue[queueCount].deltaid = this.namespace.ui + "." + itemid; queue[queueCount].store = this.store; queue[queueCount].gadget = this.gadget; queue[queueCount].widget = item.qxwidget; queue[queueCount].go = function{ toogelLoadingAtom("validating form"); //TODO: validation var delta = new Object; value = item.serialize("json"); delta[this.deltaid] = "{'event' : 'changeValue', 'value' : " + value + "}"; this.store.submitEventDelta(delta);

toogelLoadingAtom(null); if(qx.ui.core.Widget.contains(this.gadget, this.widget)) this.gadget.remove(this.widget); //remove form };	   //submit form on pressing the send button sendButton.addListener("execute", function(e){	   	queue[0].go;	    }, this); item.qxform.addButton(sendButton);

// reset button var resetButton = new qx.ui.form.Button("Reset", "icon/16/actions/dialog-cancel.png"); resetButton.addListener("execute", function {	   	item.qxform.reset;	    }, this); item.qxform.addButton(resetButton); //add formwidget to item.qxwidget item.qxwidget.view = item.qxform.createView; item.qxwidget.add(item.qxwidget.view); //add loadingAtom item.qxwidget.add(loadingAtom); return item; },	//processes the upload typed items __processUpload : function (itemid, item){ item.qxwidget = new qooxwaveclient.Upload(item.target+"", this.namespace.ui + "." + item.id, this.store, true, "multipart/form-data"); return item; },	//processes the button typed items __processButton : function (itemid, item){ if(typeof item.qxwidget == "undefined") item.qxwidget = new qx.ui.form.Button; //could be create earlier	} item.qxwidget.setLabel(item.label); var childrenToToogle = new Array; if(typeof item.subitem != "undefined"){ //loop subitems for(var subitemid in item.subitem){ if(item.subitem[subitemid].type == "form"){ //create a form item.subitem[subitemid] = this.__loop(subitemid, item.subitem[subitemid]); //for toogling on and off the forms onClick (so some lines below...) childrenToToogle.push(item.subitem[subitemid].qxwidget); }				if(item.subitem[subitemid].type == "upload"){ //create a upload form item.subitem[subitemid] = this.__loop(subitemid, item.subitem[subitemid]); //for toogling on and off the forms onClick (so some lines below...) childrenToToogle.push(item.subitem[subitemid].qxwidget); }				else continue; // make sure only allowed subitems are added }		}		//attach onClick event item.qxwidget.addListener("execute", function (event) {			//toogle forms on and off			for(var i = 0; i<childrenToToogle.length; i++){				//alert(i);				if(qx.ui.core.Widget.contains(this.gadget, childrenToToogle[i])){					this.gadget.remove(childrenToToogle[i]);				}				else{					this.gadget.add(childrenToToogle[i]);				}			}			if(typeof item.subitem == "undefined") { //only fire if there are no subitems				var delta = new Object;				var id = this.namespace.ui + "." + item.id;				delta[id] = "{'event' : 'execute'}";				//delta[id]['status'] = "fired";				this.store.submitEventDelta(delta);			}		}, this);

return item; },

//processes the checkbox typed items __processCheckbox : function (itemid, item){ if(typeof item.qxwidget == "undefined") item.qxwidget = new qx.ui.form.CheckBox; //could be create earlier	} item.qxwidget.setLabel(item.label); item.qxwidget.setValue(!!item.value); //attach onClick event item.qxwidget.addListener("changeValue", function (event) {			var delta = new Object;			var id = this.namespace.ui + "." + item.id;			delta[id] = "{\"event\" : \"changeValue\", \"value\" : \"" + event.getValue + "\"}";			this.store.submitEventDelta(delta);		}, this); return item; },	//processes the chron typed items. This item fires automated events. __processChron : function (itemid, item){ item.qxwidget = new qx.ui.groupbox.GroupBox("", null); item.qxwidget.setLayout(new qx.ui.layout.VBox(5)); item.qxwidget.setMaxWidth(300); var loadingAtom = new qx.ui.basic.Atom(""+item.label, "qooxwaveclient/ajax-loader-large.gif"); loadingAtom.set({alignX : "center"}); item.qxwidget.add(loadingAtom); var count = 1; item.chron = function{ var delta = new Object; var id = this.namespace.ui + "." + item.id; //loadingAtom.setLabel(""+count); count++; delta[id] = "{'event' : 'execute'}"; //delta[id]['status'] = "fired"; this.store.submitEventDelta(delta); };	   //create timer to regularily fire events var timer = new qx.event.Timer(parseInt(item.value)+10); timer.addListener("interval", item.chron, this); timer.start; return item; },	//processes the label typed items __processLabel : function (itemid, item){ if(typeof item.qxwidget == "undefined") item.qxwidget = new qx.ui.basic.Label(item.label); //could be create earlier	} return item; },	//processes the menu typed items __processMenu : function (itemid, item){ if(typeof item.qxwidget == "undefined") item.qxwidget = new qx.ui.menu.Button; //could be create earlier	} item.qxwidget.setLabel(item.label); var menu = new qx.ui.menu.Menu; //create a new menucontainer item.qxwidget.setMenu(menu); //and set it		if(typeof item.subitem != "undefined"){ //loop subitems for(var subitemid in item.subitem){ if(item.subitem[subitemid].type == "button"){ //if type of subitem is button, create a special menu button (design issue) item.subitem[subitemid].qxwidget = new qx.ui.menu.Button; item.subitem[subitemid] = this.__loop(subitemid, item.subitem[subitemid]); menu.add(item.subitem[subitemid].qxwidget); }				else if(item.subitem[subitemid].type == "checkbox"){ //if type of subitem is checkbox, create a special menu checkbox (design issue) item.subitem[subitemid].qxwidget = new qx.ui.menu.CheckBox; item.subitem[subitemid] = this.__loop(subitemid, item.subitem[subitemid]); menu.add(item.subitem[subitemid].qxwidget); }				else if(item.subitem[subitemid].type == "menu"){  //create a special menu (design issue) item.subitem[subitemid].qxwidget = new qx.ui.menu.Button; item.subitem[subitemid] = this.__loop(subitemid, item.subitem[subitemid]); menu.add(item.subitem[subitemid].qxwidget); }			}		}		return item; },	//Destructs this.gadget, the root gadget of the application __destructRootGadget : function { if(typeof this.gadget != "undefined" && !this.gadget.isDisposed){ this.getRoot.remove(this.gadget); this.gadget.dispose; }	},	//builds the root geadget (this,gadget) of the application. Any other gadget is added to this. this.gadget != this.getRoot __buildRootGadget : function { this.gadget = new qx.ui.container.Composite; //set an individual 'root' object called gadget. could be changed later on to calculate the correct height of the widget. Is also used to use a different layout than canvas //Set the layut of the root.gadget container var layout = new qx.ui.layout.VBox; layout.setSpacing(4); // apply spacing this.gadget.setLayout(layout); this.getRoot.add(this.gadget, {left:0, top:0, right:0}); this.gadget.addListener("resize", function{	   	  this.debug("HEIGHT: " + this.gadget.getBounds.height);	    	  this.resizeGadget;	      }, this); },	//returns a test string in qooxwave protocol form __getTestString : function { var submenu = "'submenu' : {" + "'type' : 'menu' ," + "'label' : 'Click Me' ," + "'subitem' : {'subsubmenu' : {" + "'type' : 'button' ," + "'label' : 'or click me'" + "}}" +			"}";		var upload = "'datei1' : {" + "'label' : 'Datei 1' ," + "'type' : 'upload'," + "'target' : 'http://www.davidn.de/index.php'" + "}";		var upload2 = "'datei2' : {" + "'label' : 'Datei 2' ," + "'type' : 'upload'," + "'target' : 'http://www.davidn.de/index.php'" + "}";		var formular = "'id0000' : {" + "'label' : 'Upload File' ," + "'type' : 'form'," + "'subitem' : {" + "'form_bemerkung' : {" + "'type' : 'textfield'," + "'label' : 'Bemerkung'," + "'value' : ''" + "}," +	 			"'form_checkbox1' : {" + "'type' : 'checkbox'," + "'label' : 'Aut. Erkennung'," + "'value' : true" + "}," +	 			"'form_format1' : {" + "'type' : 'radio'," + "'label' : 'Format 1'," + "'group' : 'formatgruppe'," + "'value' : 'abc'" + "}," +	 			"'form_format2' : {" + "'type' : 'radio'," + "'label' : 'Format 3'," + "'group' : 'formatgruppe'," + "'value' : false" + "}," +	 			upload + "," + upload2 + "} " +	 	"}";		return "{" +

//			formular + "," + "'rootid' : {" + "'type' : 'toolbar' ," + "'label' : 'root element' ," + "'subitem' : {" + /*		"'subid1' : {" + "'type' : 'button' ," + "'label' : 'Form'," + "'subitem' : " + "{" + 						formular + "}" +	 			"}," +*/		  		"'subid2' : {" + "'type' : 'button' ," + "'label' : 'Upload a file'," + "'subitem' : {" + upload + "}" +	 			"}," +	  			" 'subid3' : {" + "'type' : 'menu' ," + "'label' : 'Menu' ," + "'subitem' : {" + submenu + "}" +	 		"}}" +	  	"} " + 	  "}"; 	},	//builds the testing ui for debuggin. It shows state data and allows to create ui from user input strings buildTestingUI : function { var container = new qx.ui.container.Composite; this.testUi = container; var layout = new qx.ui.layout.VBox; layout.setSpacing(10); container.setLayout(layout); this.getRoot.add(container, {right: 0, top: 40});

var button = new qx.ui.form.Button("Refresh GUI (state update causes this)"); button.addListener("execute", this.refresh, this);

container.add(new qx.ui.core.Spacer(50)); container.add(new qx.ui.basic.Label("Submit a JSON-String as Delta with key " + this.namespace.ui_structure + ":")); var input = new qx.ui.form.TextArea; input.app = this; container.add(input);

var button = new qx.ui.form.Button("Submit the above input as structure"); container.add(button); button.addListener("execute", function (e){			var delta = new Object;			delta[this.app.namespace.ui_structure] = this.getValue; 			this.app.store.submitEventDelta(delta);		}, input); var button = new qx.ui.form.Button("TEST ME! (Example JSON)"); container.add(button); button.addListener("execute", function (e){			var delta = new Object;			delta[this.app.namespace.ui_structure] = this.app.__getTestString;			this.app.store.submitEventDelta(delta);			this.setValue(delta[this.app.namespace.ui_structure]);		}, input); container.add(new qx.ui.core.Spacer(50)); var info = new qx.ui.form.TextArea; info.setReadOnly(true); container.add(new qx.ui.basic.Label("Submit Delta Info:")); container.add(info); this.store.bind("modelDebug", info, "value"); } } });