--- /dev/null
+// <script type ="text/Javascript">
+GLib = imports.gi.GLib;
+Gio = imports.gi.Gio;
+
+
+
+/**
+* @namespace File
+*
+* Library to wrap GLib and Gio basic File related methods
+*
+* usage:
+*
+* File = import.File.File;
+*
+* var contents = File.read("/tmp/test.txt");
+*
+*
+*
+*/
+var File = {
+
+ SEPARATOR : '/',
+
+ // fixme - this needs a bitter location..
+ // they where in a string class before, but overriding String methods is not a good normally a good idea..
+
+ rtrim : function (s,toTrim) {
+ if (s.substr(s.length - toTrim.length) == toTrim) {
+ return s.slice(0, s.length - toTrim.length);
+ }
+
+ return s;
+ },
+ trim : function (s,toTrim) {
+ var out = s.ltrim(toTrim);
+ out = out.rtrim(toTrim);
+ return out;
+ },
+
+ ltrim : function (s, toTrim) {
+ if (s.substr(0, toTrim.length) == toTrim) {
+ return s.slice(toTrim.length);
+ }
+
+ return s;
+ },
+
+ join : function () {
+ var out = "";
+ for (var i = 0; i < arguments.length; i++) {
+ if (i == 0) {
+ out += this.rtrim(arguments[i], File.SEPARATOR);
+ }
+ else if (i == arguments.length - 1) {
+ out += File.SEPARATOR + this.ltrim(arguments[i], File.SEPARATOR);
+ }
+ else {
+ out += File.SEPARATOR + this.trim(arguments[i], File.SEPARATOR);
+ }
+ }
+ return out;
+ },
+
+ dirname : function(s)
+ {
+ var ar = s.split(File.SEPARATOR);
+ ar.pop();
+ return ar.join(File.SEPARATOR);
+ },
+ basename : function(s)
+ {
+ var ar = s.split(File.SEPARATOR);
+ return ar.pop();
+ },
+
+ read : function (path) {
+ var out = {};
+ GLib.file_get_contents(path, out, null, null);
+
+ //print(JSON.stringify(out));
+
+ return out['value'];
+ },
+
+ isFile : function (path) {
+ return GLib.file_test(path, GLib.FileTest.IS_REGULAR);
+ },
+ exists : function (path) {
+ return GLib.file_test(path, GLib.FileTest.EXISTS);
+ },
+ isDirectory : function (path) {
+ return GLib.file_test(path, GLib.FileTest.IS_DIR);
+ },
+
+ list : function (path) {
+ var listing = [];
+ print(path);
+ var f = Gio.file_new_for_path(String(path));
+ var file_enum = f.enumerate_children(Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, Gio.FileQueryInfoFlags.NONE, null);
+
+ var next_file = null;
+
+ while ((next_file = file_enum.next_file(null)) != null) {
+ listing.push(next_file.get_display_name());
+ }
+
+ file_enum.close(null);
+
+ listing.sort();
+
+ return listing;
+ },
+
+ mtime : function (path) {
+ var f = Gio.file_new_for_path(String(path));
+ var mtime = new GLib.TimeVal();
+
+ var info = f.query_info(Gio.FILE_ATTRIBUTE_TIME_MODIFIED, Gio.FileQueryInfoFlags.NONE, null);
+ info.get_modification_time(mtime);
+
+ return new Date(mtime.tv_sec * 1000);
+ },
+
+ /**
+ * resolve the real path
+ * @arg path {String} Path to resolve
+ * @returns {String} the resolved path path.
+ *
+ */
+ realpath : function (path) {
+ return this.canonical(path);
+ },
+ canonical : function (path) {
+ var f = Gio.file_new_for_path(String(path));
+ var can = f.resolve_relative_path('');
+ return can.get_path();
+ },
+ /**
+ * write a string to a file
+ * @arg path {String} File to write to alwasy overwrites.
+ * @arg string {String} Contents of file.
+ *
+ */
+ write : function (path, string) {
+ var d = new Date();
+ var f = Gio.file_new_for_path(String(path));
+ var data_out = new Gio.DataOutputStream({base_stream:f.replace(null, false, Gio.FileCreateFlags.NONE, null)});
+ data_out.put_string(string, null);
+ data_out.close(null);
+ print("WRITE : " + path + " in " + ((new Date()) - d) + 'ms');
+
+ },
+ /**
+ * append
+ * @arg path {String} File to write to
+ * @arg string {String} string to append to file.
+ *
+ */
+ append : function (path, string) {
+ var f = Gio.file_new_for_path(String(path));
+ var data_out = new Gio.DataOutputStream({
+ base_stream:f.append_to(Gio.FileCreateFlags.NONE, null)
+ });
+ data_out.put_string(string, null);
+ data_out.close(null);
+ },
+ /**
+ * remove
+ * Delete a file.
+ * @arg path {String} File to remove
+ *
+ *
+ */
+ remove : function (path)
+ {
+ var f = Gio.file_new_for_path(String(path));
+ return f['delete']();
+ },
+ // copy files recursively from fromDir, silently ignore them if they already exist in toDir
+ silentRecursiveCopy : function (fromDir, toDir) {
+ var filesToCopy = File.recursiveListing(fromDir);
+ var srcPath, destPath, src, dest;
+
+ for (var index in filesToCopy) {
+ srcPath = File.join(String(fromDir), filesToCopy[index]);
+ destPath = File.join(String(toDir), filesToCopy[index]);
+
+ if (File.isFile(srcPath) && !File.isFile(destPath)) {
+ File.copyFile(srcPath, destPath);
+ }
+ else if (File.isDirectory(srcPath) && !File.isDirectory(destPath)) {
+ File.mkdir(destPath);
+ }
+
+ }
+ },
+ /**
+ * Make a symbolic link
+ * @arg new_link {String} The new link
+ * @arg target {String} Where it links to.
+ */
+ link : function (new_link, target) {
+ var dest = Gio.file_new_for_path(String(new_link));
+ return dest.make_symbolic_link(target, null);
+ },
+ /**
+ * Make a directory
+ * FIXME - needs perms setting..
+ *
+ * @arg directory {String} Directory to make
+ */
+
+ mkdir : function (destPath) {
+ var dest = Gio.file_new_for_path(String(destPath));
+ return dest.make_directory(null);
+ },
+
+ /**
+ * Copy a file or (directory maybe?)
+ * @arg srcPath {String} source file
+ * @arg destPath {String} destination file
+ * @arg flags {Gio.FileCopyFlags} to overwrite etc... Gio.FileCopyFlags.OVERWRITE
+ */
+ copy : function (srcPath, destPath, flags) {
+ return this.copyFile(srcPath, destPath, flags);
+ },
+ copyFile : function (srcPath, destPath, flags) {
+
+ flags = typeof(flags) == 'undefined' ? Gio.FileCopyFlags.NONE : flags;
+ var dest = Gio.file_new_for_path(String(destPath));
+ var src = Gio.file_new_for_path(String(srcPath));
+
+ // a bit of a hack for the fact that Gio.File.copy arguments
+ // can be nulled, but not according to the GIR file
+ return src.copy(dest, flags);
+ },
+
+
+
+
+ recursiveListing : function (dir) {
+
+ function recursiveListingInternal(prefix, listing, dir) {
+ var entries = File.list(dir);
+ var next, fullPath;
+
+ for (var index in entries) {
+ next = entries[index];
+ fullPath = File.join(prefix, dir, next);
+
+ if (File.isDirectory(fullPath)) {
+ listing.push(next);
+ listing = listing.concat(recursiveListingInternal(next, [], fullPath));
+ }
+ else {
+ if (prefix) {
+ next = File.join(prefix, next);
+ }
+ listing.push(next);
+ }
+ }
+
+ return listing;
+ }
+
+ return recursiveListingInternal('', [], dir);
+ }
+
+};
--- /dev/null
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+
+
+atoms = {
+ "STRING" : Gdk.atom_intern("STRING")
+ };
+targetList = new Gtk.TargetList();
+targetList.add( atoms["STRING"], 0, 0);
+
+
+
+Gtk.rc_parse_string(
+ "style \"gtkcombobox-style\" {\n" +
+ " GtkComboBox::appears-as-list = 1\n" +
+ "}\n"+
+ "class \"GtkComboBox\" style \"gtkcombobox-style\"\n");
+
+
+//imports.Window.Window.el.show_all();
--- /dev/null
+//<script type="text/javscript">
+
+XObject = imports.XObject.XObject;
+console = imports.console.console;
+Collapse = imports.JSDOC.Collapse.Collapse;
+/**
+ *
+ * this takes our collased file, and turns it into the config array..
+ *
+ * @see rconv.js (our tester file)
+ *
+ * STATUS:
+ *
+ * - Pman.Tab.* appears to work.
+ * .. next up ..Dialog...
+ *
+ *
+ *
+ * Current issues:
+ * - xtype is combined on generated files. (not xns + xtype)
+ * - listeners are prefixed with '|' ...
+ * - modkey is not getting picked up..
+ * - suspect some of the elements are not getting flattened
+ * - parent on
+ */
+
+JsParser = XObject.define(
+ function (ar)
+ {
+ JsParser.superclass.constructor.call(this, ar);
+ // console.log("STARTING OUTPUT");
+
+
+
+ },
+ Collapse,
+ {
+
+ cfg : { },
+
+ parse: function()
+ {
+ // standard pman dialog
+ if (this.tokens[0].data == 'Pman.on') {
+ this.parsePmanLayout();
+ return;
+ }
+
+
+ // Standard Pman Dialog -
+ if (this.tokens[2].props && typeof(this.tokens[2].props.create) != 'undefined') {
+ this.parsePmanDialog();
+ return;
+ }
+
+
+ // Seed Gtk XObject application.
+ if (this.tokens.length > 2 && this.tokens[2].data.match(/^imports\./)) {
+ this.parseXObject();
+ return;
+ }
+
+ Seed.print("Unknown format");
+ Seed.print(JSON.stringify(this.tokens,null,4));
+ Seed.quit();
+
+
+
+
+
+
+
+
+ // perfect for dialogs... - is this our 'generic, non-pman code?'
+
+
+ var pos = this.lookFor( 'function');
+
+ // XXXXX = function(
+ var cfg = {};
+
+ if (pos > -1 && (this.tokens[pos-1].data == '=') && (this.tokens[pos-2].type == 'NAME')) {
+
+ this.cfg = {
+ '*class' : this.tokens[pos-2].data,
+ '*extends' : '',
+ '//constructor' : this.tokens[pos-2].prefix,
+ '|constructor' : 'function ' + this.tokens[pos+1].toRaw() +
+ this.tokens[pos+2].toRaw()
+
+ };
+ this.cursor = pos+2;
+
+ }
+
+ if (pos < 0) {
+ // no function - we have a static one...
+ pos = this.lookFor( '=');
+ if (pos > 1 &&
+ (this.tokens[pos-1].type == 'NAME') &&
+ (this.tokens[pos+1].data == '{')
+ ) {
+ this.cfg = {
+ '*class' : this.tokens[pos-1].data,
+ '//*class' : this.tokens[pos-1].prefix
+
+
+ };
+ XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].props));
+ return;
+
+ }
+
+
+
+ }
+
+
+ // Roo.apply (l
+ var pos = this.lookFor( 'Roo.apply');
+ //console.dump(this.tokens);
+
+
+ if (
+ (pos > -1) &&
+ (this.tokens[pos+1].items[0][0].data == this.cfg['*class'] + '.prototype')
+ ) {
+ // XXXXXx.prototype = {
+
+
+
+ XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].items[1][0].props));
+ return;
+
+ }
+
+
+ var pos = this.lookFor('new');
+
+ if (pos > -1 &&
+ (this.tokens[pos-2].type == 'NAME') &&
+ (this.tokens[pos-1].data == '=') &&
+ (this.tokens[pos+1].type == 'NAME') &&
+ (this.tokens[pos+2].data == '(')
+ ) {
+
+ this.cfg = {
+ '//*class' : this.tokens[pos-2].prefix,
+ '*class' : this.tokens[pos-2].data,
+ '*extends' : this.tokens[pos+1].data
+ };
+
+ XObject.extend(this.cfg, this.parseProps(this.tokens[pos+2].items[0][0].props));
+
+ return;
+
+ }
+
+ ///Builder.Provider.ProjectManager = new Roo.Observable({
+
+
+
+ var pos = this.lookFor( 'Roo.extend');
+ if (pos > -1) {
+
+ this.cfg['*extends'] = this.tokens[pos+1].items[1][0].data;
+ XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].items[2][0].props));
+
+ // no more..
+ return;
+ }
+
+
+
+ var pos = this.lookFor( 'Roo.extend');
+ if (pos > -1) {
+
+ this.cfg['*extends'] = this.tokens[pos+1].items[1][0].data;
+ XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].items[2][0].props));
+
+ // no more..
+ return;
+ }
+
+
+
+ //console.dump(cfg);
+ //Seed.quit();
+
+
+
+ // other type of layout
+ // console.dump(this.tokens);
+
+ // this type of file..
+ // xxxx.xxx = function
+ // -> into |constructor..
+ // -> extend + prototype
+
+
+
+
+ },
+
+
+ parsePmanLayout : function()
+ {
+ // then it's a layout style..
+
+ //Seed.quit();
+
+
+ //console.dump(this.tokens);
+ // the list of statements inside of function..?
+
+
+ var stmts = this.tokens[1].items[1][2].items;
+
+ // look for register..
+ var topp = false;
+ stmts.map( function(s, i) {
+ if (s[0].data == 'Pman.register') {
+ topp = brace = s[1].items[0][0].props;
+ }
+ });
+ if (!topp) {
+ console.dump(this.tokens);
+ throw "could not find top props...";
+
+ }
+ //print(JSON.stringify(topp,null,4));
+
+ this.cfg = this.parseProps(topp);
+ for(var k in this.cfg) {
+ this.cfg[k.replace(/^\|/, '')] = this.cfg[k];
+ }
+ if (this.cfg.name) {
+ this.cfg.title = this.cfg.name;
+ delete this.cfg.name;
+ }
+ // this.cfg.fullname = this.cfg.name;
+ this.cfg.type = 'Roo';
+
+
+
+ // looking for parent / name..
+
+
+ this.cfg.modOrder = this.cfg.modKey.split('-').shift();
+ print(JSON.stringify(this.cfg,null,4));
+
+
+ // ( { add { this.panel ( {
+ var cfg = this.tokens[7].items[0][0].props.add.val[2].items[2][3].items[0][0].props;
+ this.cfg.items = [ this.parseProps(cfg) ];
+ //console.dump(this.cfg);
+ },
+
+
+ parsePmanDialog : function() {
+
+ //console.dump(this.tokens);
+ this.cfg.name = this.tokens[0].data;
+
+
+
+ var cfg = this.tokens[2].props.create.val[2].items[1][3].items[0][0].props;
+ this.cfg.type = 'Roo';
+ //console.dump(this.tokens);
+ //print(JSON.stringify(cfg,null,4)); Seed.quit();
+
+ // print("Trying standard dialog");Seed.quit();;
+
+ this.cfg.items = [ this.parseProps(cfg) ];
+ return;
+
+ },
+
+ // Seed xobject file.
+ parseXObject : function() {
+
+ this.parseImports();
+
+ var pos = this.lookFor('XObject');
+ if (pos < 0) {
+ throw "Can not find XObject";
+ }
+ this.cfg.name = this.tokens[pos-3].data;
+ this.cfg.type = 'Gtk';
+ var cfg = this.tokens[pos+1].items[0][0].props;
+ this.cfg.items = [ this.parseProps(cfg) ];
+
+ //print(JSON.stringify(this.tokens[pos]));
+
+ //print(JSON.stringify(this.tokens,null,4)); Seed.quit();
+ //Seed.quit();
+
+ },
+
+
+
+ /**
+ * parse Imports lines.
+ *
+ */
+
+ parseImports : function()
+ {
+ // console.dump(this.tokens);
+ this.cfg.giImports = [];
+ this.cfg.imports= [];
+ while (true) {
+ var pos = this.lookFor('=');
+ if (pos < 0) {
+ break;
+ }
+ this.cursor = pos;
+ var k = this.look(-1, true);
+ var v = this.look(1, true);
+ // Seed.print(k.data + " => " + v.data);
+
+ /// finish!!! - not an import ...
+
+ if (!v.data.match(/^imports/)) {
+ return; ///
+
+ this.cursor++;
+ continue;
+ }
+ if (v.data.match(/^imports\.gi/)) {
+ // gi import..
+ this.cfg.giImports.push(v.data.replace(/imports\.gi\./, ''));
+
+ this.cursor++;
+ continue;
+ }
+
+ // two types of import left
+ // imports.xnew
+ if (v.data.match(/^imports\./)) {
+ this.cfg.imports[k.data] = v.data.replace(/imports\./, '') + '.js';
+ this.cursor++;
+ continue;
+ }
+ // imports[.....]
+ this.cursor++;
+ if (this.lookFor('[') > this.lookFor('=')) {
+ continue;
+ }
+ var bpos = this.lookFor('[');
+ // console.dump(this.tokens[bpos]);
+
+ this.cfg.imports[k.data] = this.tokens[bpos].items[0][0].toJS();
+
+ this.cursor++;
+
+ }
+ // console.dump(this.giImports);
+ // console.dump(this.imports);
+ //Seed.quit();
+
+ },
+
+ ///------------------- GENERIC PARSING ------------------
+
+
+
+
+
+
+ parseProps: function(o)
+ {
+ //print(JSON.stringify(o,null,4));
+
+ var ret = { };
+ var fakeItems = [];
+ for(var k in o) {
+
+ //print( "parsing prop: " + k);
+ if (o[k].key.data == '}') {
+ // typo trailing comma in object def.
+ continue;
+ }
+
+ var kv = k;
+ if (o[k].key.type == 'STRN') {
+ kv = o[k].key.toJS();
+ }
+ if (!o[k].val.length) {
+ console.dump(o[k]);
+ }
+
+ //console.dump(o[k]);
+ if (o[k].val[0].data == "function") {
+ // add comments..
+ // console.dump(o[k].key.prefix);
+ var pr = typeof(o[k].key.prefix) == 'undefined' ? '' : o[k].key.prefix ;
+ pr = this.clean_prefix( pr) ;
+ if (pr.length) {
+ ret['//' +kv ] = pr;
+ }
+ //print("running expand");
+ ret['|' +kv ] = this.clean_body( this.expand(o[k].val));
+ continue;
+ }
+
+
+ if (o[k].val[0].data == "[") {
+
+ if (o[k].val[0].items[0][0].data == '{') {
+ // array of objects..
+
+ // this works for items..
+
+ // used elsewhere for buttons: -> in which case we have a fake xtype
+
+
+
+ // if K is not ITEMS - we need to add '*prop' -> and add it to the items array..
+ var add = this.parseArray(o[k].val[0].items);
+ if (kv == 'items') {
+ ret[kv] = add;
+ continue;
+ }
+ add.forEach(function(a) {
+ a['*prop'] = kv + '[]';
+ fakeItems.push(a);
+ });
+
+ continue;
+ }
+ // raw array
+
+
+ ret['|' +kv ] = this.clean_body(this.expand(o[k].val)); // remove ','...
+ continue;
+ }
+ if (o[k].val[0].data == "(") {
+ ret['|' +kv ] = this.expand(o[k].val);
+ continue;
+ }
+ // value is an object..
+
+ if (o[k].val[0].data == "{") {
+
+ // things that can be property of object type:
+ // listeners, set,
+ var add = this.parseProps(o[k].val[0].props);
+
+
+
+ if (kv == 'set' || kv =='listeners') {
+ ret[kv ] = add;
+ continue;
+ }
+ if ((typeof(add.xtype) != 'undefined') || ['sortInfo', 'center', 'east', 'west', 'north', 'south'].indexOf(kv) > -1) {
+ add['*prop'] = kv;
+ fakeItems.push(add);
+ continue;
+ }
+
+
+ ret[ '|' + kv ] = this.expand(o[k].val);
+
+
+ // this hsould be added to 'items', with a *prop element..
+ continue;
+ }
+ //console.dump(o[k].val);
+
+ if (o[k].val[1].data == ',' || o[k].val[1].data == '}') {
+ // single item piece of data...
+ var t1= o[k].val[0];
+ switch(o[k].val[0].type) {
+ case 'STRN':
+ case 'NUMB':
+ case 'KEYW':
+ ret[ kv ] = t1.toJS();
+ continue;
+ case 'NAME':
+ ret[ '|' + kv ] = t1.data;
+ continue;
+
+ }
+ }
+ // finally give up..
+ ret[ '|' + kv ] = this.clean_body(this.expand(o[k].val));
+
+ }
+ if (!ret.items && fakeItems.length) {
+ ret.items = [];
+ }
+ fakeItems.forEach( function(e) {
+ ret.items.push(e);
+ });
+ // merge fakeItems;
+ //console.dump(ret);
+
+ return ret;
+ },
+ parseArray: function(ar) {
+ // console.dump(ar);
+ // Seed.quit();
+ var ret = [];
+ ar.map(function (e) {
+ // has no props...
+ if (typeof(e[0].props) == 'undefined') {
+ return;
+ }
+
+
+ ret.push( this.parseProps(e[0].props));
+
+ },this);
+
+ return ret;
+
+ },
+
+ /**
+ * convert a function call token array back into a string
+ */
+ expand: function(ar)
+ {
+ var ret = '';
+ //print(JSON.stringify(ar,null,4));
+
+ for(var i =0 ; i < ar.length -1; i++) {
+ ret += ar[i].toRaw();
+ }
+
+ return ret;
+
+
+ },
+
+ /***
+ * change the indentation on a function
+ *
+ */
+ clean_body : function(str)
+ {
+ var lns = str.split("\n");
+ var mindent = -1;
+ lns.map( function(l, i) {
+ if (!i || !l.length || l.match(/^\s+$/)) {
+ return;
+ }
+
+ var spc = l.match(/\s+/);
+ if (!spc || !spc[0].length) {
+ return;
+ }
+ mindent = mindent < 0 ? spc[0].length : Math.min(spc[0].length, mindent);
+
+ });
+ //console.log(mindent + ":" + lns[0]);
+ var ar = [];
+ if (mindent < 0) {
+ return str;
+ }
+ lns.map( function(l,i) {
+ if (!i) {
+ ar.push(l.replace(/^\s+/, ''));
+ return;
+ }
+ ar.push(l.substring(mindent));
+ });
+ //print(str);
+ //print(JSON.stringify(ar,null,4));
+
+
+ return ar.join("\n");
+ },
+ clean_prefix: function(str) {
+
+
+
+ if (!str.length) {
+ return '';
+ }
+ var ret = str.replace(/^\s+/gm, "\n").replace(/\n+/gm, "\n");
+ return ret == "\n" ? '' : ret;
+
+ }
+
+
+});
\ No newline at end of file
--- /dev/null
+/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+XObject = imports.XObject.XObject;
+/**
+ * @class Observable
+ * Base class that provides a common interface for publishing events. Subclasses are expected to
+ * to have a property "events" with all the events defined.<br>
+ * For example:
+ * <pre><code>
+ Employee = XObject.define(
+ function(name){
+ this.name = name;
+ this.addEvents({
+ "fired" : true,
+ "quit" : true
+ });
+ },
+ Observable, {});
+
+</code></pre>
+ * @param {Object} config properties to use (incuding events / listeners)
+ */
+
+
+Observable = XObject.define(
+ function(cfg){
+
+ cfg = cfg|| {};
+ this.addEvents(cfg.events || {});
+ if (cfg.events) {
+ delete cfg.events; // make sure
+ }
+
+ XObject.extend(this, cfg);
+
+ if(this.listeners){
+ this.on(this.listeners);
+ delete this.listeners;
+ }
+ },
+ Object,
+ {
+ /**
+ * @cfg {Object} listeners list of events and functions to call for this object,
+ * For example :
+ * <pre><code>
+ listeners : {
+ 'click' : function(e) {
+ .....
+ } ,
+ ....
+ }
+ </code></pre>
+ */
+
+
+ /**
+ * Fires the specified event with the passed parameters (minus the event name).
+ * @param {String} eventName
+ * @param {Object...} args Variable number of parameters are passed to handlers
+ * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
+ */
+ fireEvent : function(){
+ var ce = this.events[arguments[0].toLowerCase()];
+ if(typeof ce == "object"){
+ return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
+ }else{
+ return true;
+ }
+ },
+
+ // private - blcoks these types of signals?
+ filterOptRe : /^(?:scope|delay|buffer|single)$/,
+
+ /**
+ * Appends an event handler to this component
+ * @param {String} eventName The type of event to listen for
+ * @param {Function} handler The method the event invokes
+ * @param {Object} scope (optional) The scope in which to execute the handler
+ * function. The handler function's "this" context.
+ * @param {Object} options (optional) An object containing handler configuration
+ * properties. This may contain any of the following properties:<ul>
+ * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
+ * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.NOT AVAIALBLE</li>
+ * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
+ * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link DelayedEvent} delayed NOT AVAIALBLE
+ * by the specified number of milliseconds. If the event fires again within that time, the original
+ * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
+ * </ul><br>
+ * <p>
+ * <b>Combining Options</b><br>
+ * Using the options argument, it is possible to combine different types of listeners:<br>
+ * <br>
+ * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
+ <pre><code>
+ el.on('click', this.onClick, this, {
+ single: true,
+ delay: 100,
+ forumId: 4
+ });
+ </code></pre>
+ * <p>
+ * <b>Attaching multiple handlers in 1 call</b><br>
+ * The method also allows for a single argument to be passed which is a config object containing properties
+ * which specify multiple handlers.
+ * <pre><code>
+ el.on({
+ 'click': {
+ fn: this.onClick,
+ scope: this,
+ delay: 100
+ },
+ 'mouseover': {
+ fn: this.onMouseOver,
+ scope: this
+ },
+ 'mouseout': {
+ fn: this.onMouseOut,
+ scope: this
+ }
+ });
+ </code></pre>
+ * <p>
+ * Or a shorthand syntax which passes the same scope object to all handlers:
+ <pre><code>
+ el.on({
+ 'click': this.onClick,
+ 'mouseover': this.onMouseOver,
+ 'mouseout': this.onMouseOut,
+ scope: this
+ });
+ </code></pre>
+ */
+ on : function(eventName, fn, scope, o){
+ if(typeof eventName == "object"){
+ o = eventName;
+ for(var e in o){
+ if(this.filterOptRe.test(e)){
+ continue;
+ }
+ if(typeof o[e] == "function"){
+ // shared options
+ this.on(e, o[e], o.scope, o);
+ }else{
+ // individual options
+ this.on(e, o[e].fn, o[e].scope, o[e]);
+ }
+ }
+ return;
+ }
+ o = (!o || typeof o == "boolean") ? {} : o;
+ eventName = eventName.toLowerCase();
+ var ce = this.events[eventName] || true;
+ if(typeof ce == "boolean"){
+ ce = new Event(this, eventName);
+ this.events[eventName] = ce;
+ }
+ ce.addListener(fn, scope, o);
+ },
+
+ /**
+ * Removes a listener
+ * @param {String} eventName The type of event to listen for
+ * @param {Function} handler The handler to remove
+ * @param {Object} scope (optional) The scope (this object) for the handler
+ */
+ un : function(eventName, fn, scope){
+ var ce = this.events[eventName.toLowerCase()];
+ if(typeof ce == "object"){
+ ce.removeListener(fn, scope);
+ }
+ },
+
+ /**
+ * Removes all listeners for this object
+ */
+ purgeListeners : function(){
+ for(var evt in this.events){
+ if(typeof this.events[evt] == "object"){
+ this.events[evt].clearListeners();
+ }
+ }
+ },
+ _combine : function(){
+ var as = arguments, l = as.length, r = [];
+ for(var i = 0; i < l; i++){
+ var a = as[i];
+ if(a instanceof Array){
+ r = r.concat(a);
+ }else if(a.length !== undefined && !a.substr){
+ r = r.concat(Array.prototype.slice.call(a, 0));
+ }else{
+ r.push(a);
+ }
+ }
+ return r;
+ },
+
+ relayEvents : function(o, events){
+ var createHandler = function(ename){
+ return function(){
+ return this.fireEvent.apply(this, Event.prototype.combine(ename,
+ Array.prototype.slice.call(arguments, 0)));
+ };
+ };
+ for(var i = 0, len = events.length; i < len; i++){
+ var ename = events[i];
+ if(!this.events[ename]){ this.events[ename] = true; };
+ o.on(ename, createHandler(ename), this);
+ }
+ },
+
+ /**
+ * Used to define events on this Observable
+ * @param {Object} object The object with the events defined
+ */
+ addEvents : function(o){
+ if(!this.events){
+ this.events = {};
+ }
+ XObject.extendIf(this.events, o);
+ },
+
+ /**
+ * Checks to see if this object has any listeners for a specified event
+ * @param {String} eventName The name of the event to check for
+ * @return {Boolean} True if the event is being listened for, else false
+ */
+ hasListener : function(eventName){
+ var e = this.events[eventName];
+ return typeof e == "object" && e.listeners.length > 0;
+ }
+});
+
+/**
+ * Starts capture on the specified Observable. All events will be passed
+ * to the supplied function with the event name + standard signature of the event
+ * <b>before</b> the event is fired. If the supplied function returns false,
+ * the event will not fire.
+ * @param {Observable} o The Observable to capture
+ * @param {Function} fn The function to call
+ * @param {Object} scope (optional) The scope (this object) for the fn
+ * @static
+ */
+Observable.capture = function(o, fn, scope){
+ o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
+};
+
+/**
+ * Removes <b>all</b> added captures from the Observable.
+ * @param {Observable} o The Observable to release
+ * @static
+ */
+Observable.releaseCapture = function(o){
+ o.fireEvent = Observable.prototype.fireEvent;
+};
+
+
+
+var createSingle = function(h, e, fn, scope){
+ return function(){
+ e.removeListener(fn, scope);
+ return h.apply(scope, arguments);
+ };
+};
+
+// NOT SUPPORTED YET>
+//var createBuffered = function(h, o, scope){
+// var task = new DelayedTask();
+// return function(){
+// task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
+// };
+//};
+
+
+//var createDelayed = function(h, o, scope){
+// return function(){
+// var args = Array.prototype.slice.call(arguments, 0);
+// setTimeout(function(){
+// h.apply(scope, args);
+// }, o.delay || 10);
+// };
+//};
+
+
+/**
+ * Event Object - manages a specific event.
+ *
+ *
+ *
+ */
+
+
+
+Event = XObject.define(
+ function(obj, name){
+ this.name = name;
+ this.obj = obj;
+ this.listeners = [];
+ },
+ Object,
+ {
+ addListener : function(fn, scope, options){
+ var o = options || {};
+ scope = scope || this.obj;
+ if(!this.isListening(fn, scope)){
+ var l = {fn: fn, scope: scope, options: o};
+ var h = fn;
+ // if(o.delay){
+ // h = createDelayed(h, o, scope);
+ // }
+ if(o.single){
+ h = createSingle(h, this, fn, scope);
+ }
+ //if(o.buffer){
+ // h = createBuffered(h, o, scope);
+ //}
+ l.fireFn = h;
+ if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
+ this.listeners.push(l);
+ }else{
+ this.listeners = this.listeners.slice(0);
+ this.listeners.push(l);
+ }
+ }
+ },
+
+ findListener : function(fn, scope){
+ scope = scope || this.obj;
+ var ls = this.listeners;
+ for(var i = 0, len = ls.length; i < len; i++){
+ var l = ls[i];
+ if(l.fn == fn && l.scope == scope){
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ isListening : function(fn, scope){
+ return this.findListener(fn, scope) != -1;
+ },
+
+ removeListener : function(fn, scope){
+ var index;
+ if((index = this.findListener(fn, scope)) != -1){
+ if(!this.firing){
+ this.listeners.splice(index, 1);
+ }else{
+ this.listeners = this.listeners.slice(0);
+ this.listeners.splice(index, 1);
+ }
+ return true;
+ }
+ return false;
+ },
+
+ clearListeners : function(){
+ this.listeners = [];
+ },
+
+ fire : function(){
+ var ls = this.listeners, scope, len = ls.length;
+ if(len > 0){
+ this.firing = true;
+ var args = Array.prototype.slice.call(arguments, 0);
+ for(var i = 0; i < len; i++){
+ var l = ls[i];
+ if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
+ this.firing = false;
+ return false;
+ }
+ }
+ this.firing = false;
+ }
+ return true;
+ }
+ }
+);
--- /dev/null
+//<script type="text/javascript">
+
+XObject = imports.XObject.XObject
+
+/**
+ * Options parsing is needed as GLib's built in GOptionGroup is not feasible to use in an introspected way at present.
+ *
+ * usage :
+ *
+ * o = new Options(
+ * help_desription : 'Help about this',
+ * options : [
+ * { arg_short : 'a', arg_long: 'test', description : 'a test', flag_array: true , flag_boolean : false, arg_default: 'fred'}
+ * ]
+ * );
+ * cfg = o.parse(Seed.argv);
+ *
+ * Currently only supports simple parsing
+ * eg. --longarg test -b test
+ *
+ * Does not support --aaaaa=bbbb
+ */
+Options = XObject.define(
+ function (cfg) {
+ options = []; // default.
+ XObject.extend(this,cfg);
+ if (this.help_description.length) {
+ this.options.push({ arg_short : 'h', arg_long: 'help', description : 'Show Help', flag_boolean : true});
+
+ }
+ },
+ Object,
+ {
+ /**
+ * @cfg {String} help_description what appears at the start of the help message.
+ */
+ help_description: '',
+ /**
+ * @cfg {Boolean} If extra arguments are allowed.
+ */
+ allow_extra : false,
+ /**
+ * @param {Object} Resulting key/value of data.
+ */
+ result : false,
+ /**
+ * @prop {Array} the arguments
+ */
+ args: false,
+ /**
+ * @prop {Array} extra the arguments that are not accounted for.
+ */
+ extra: false,
+ /**
+ * parse the argv
+ * usage: options.parse(Seed.argv)
+ */
+ parse: function (argv)
+ {
+ var _this = this;
+ this.result = {};
+ this.options.forEach(function(a) {
+
+ if (typeof(a.arg_default) != 'undefined') {
+ _this.result[a.arg_long] = a.arg_default;
+ return;
+ }
+
+ if (a.flag_boolean) {
+ _this.result[a.arg_long] = false;
+ return;
+ }
+ if (a.flag_array) {
+ _this.result[a.arg_long] = [];
+ return;
+ }
+
+ })
+
+ this.extra = {};
+ var args = Array.prototype.slice.call(Seed.argv);
+ args.shift(); //seed
+ args.shift(); //script..
+
+ for(var i =0; i < args.length;i++) {
+
+ var a= this.findArg(args[i]);
+
+ if (!a) {
+ if (!this.allow_extra) {
+ throw {
+ name: "ArgumentError",
+ message: "Unknown argument: " + args[i]
+ };
+ }
+ this.extra.push(args[i]);
+ }
+
+ if (a.arg_long == 'help' ) {
+ print("Help Message Requested");
+ this.showHelp();
+ Seed.quit();
+ return;
+ }
+
+ if (a.flag_boolean) {
+ this.result[a.arg_long] = true;
+ continue;
+ }
+ var next = args[i+1];
+ if (this.findArg(next)) {
+ throw {
+ name: "ArgumentError",
+ message: "Invalid argument sequence: " + args[i] + ' ' + next
+ };
+ }
+ // type juggling -- fixme...
+
+ if (a.flag_array) {
+ this.result[a.arg_long].push(next);
+ i++;
+ continue;
+ }
+
+ if (typeof(this.result[a.arg_long]) != 'undefined' && this.result[a.arg_long] != a.arg_default) {
+ throw {
+ name: "ArgumentError",
+ message: "Invalid argument duplicate: " + args[i] + ' ' + next
+ };
+ }
+
+ this.result[a.arg_long] = next;
+ i++;
+ }
+ // validate results..
+ this.options.forEach(function(a) {
+ if (typeof(a.arg_default) != 'undefined') {
+ return;
+ }
+ if (a.flag_boolean) {
+ return;
+ }
+ if (typeof(_this.result[a.arg_long]) != 'undefined') {
+ return;
+ }
+ _this.showHelp();
+ throw {
+ name: "ArgumentError",
+ message: "Missing Argument: --" + a.arg_long
+ };
+ });
+
+
+ return this.result;
+ },
+
+
+ findArg : function(str)
+ {
+ var ret = false;
+ var type = str.substring(0,1) == '-' ? 'arg_short' : '';
+ type = str.substring(0,2) == '--' ? 'arg_long' : type;
+ if (type == '') {
+ return false; // not an arg..
+ }
+ var match = str.substring(type =='arg_long' ? 2 : 1);
+
+ this.options.forEach(function(o) {
+ if (ret) {
+ return; // no more parsing.
+ }
+ if (o[type] == match) {
+ ret = o;
+ }
+
+ });
+ return ret;
+
+ },
+
+
+ showHelp: function()
+ {
+ print(this.help_description);
+ this.options.forEach(function(o) {
+ // fixme needs tidying up..
+ print(' --' + o.arg_long + ' (-' + o.arg_short + ') ' + o.description);
+ });
+
+
+ }
+ }
+);
--- /dev/null
+//<Script type="text/javascript">
+Gio = imports.gi.Gio;
+GLib = imports.gi.GLib;
+
+
+console = imports.console;
+XObject = imports.XObject.XObject;
+
+Observable = imports.Observable.Observable;
+File = imports.File.File;
+/**
+ *
+ * /home/alan/.BuilderConfig/*
+ *
+ *
+ */
+
+ProjectManager = new Observable({
+
+ events : {
+ 'changed' : true
+ },
+
+
+ listeners : {
+ 'changed' : function() {
+ this.saveConfig();
+ }
+
+ },
+
+ palete : { },
+ projects : [],
+ filename : false,
+
+ loadConfig : function ()
+ {
+ // we can not do this async....
+ this.dirname = GLib.get_home_dir() + '/.Builder';
+
+ var dir = Gio.file_new_for_path(this.dirname);
+ if (!dir.query_exists()) {
+ dir.make_directory();
+ return;
+ }
+
+ this.projects = [];
+ var files = File.list(this.dirname);
+
+
+ //print(files);Seed.quit();
+ for (var i =0 ; i < files.length;i++) {
+ var fn = files[i];
+ print(fn);
+ if (!fn.match(/\.json$/)) {
+ continue;
+ }
+ var str = File.read(this.dirname + '/' + fn);
+ if (!str || !str.length) {
+ print("EMPTY");
+ continue; // empty file.
+ }
+
+
+ var ar = JSON.parse(str);
+ Seed.print(ar.xtype);
+
+ // construct...
+ var cls = imports.Project[ar.xtype][ar.xtype];
+ this.projects.push( new cls(ar));
+
+
+
+
+
+
+ }
+// print(JSON.stringify(this.projects.length));Seed.quit();
+
+ this.projects.sort(function(a,b) {
+ if (a.getName() == b.getName()) {
+ return 0;
+ }
+ return a.getName() > b.getName() ? 1 : -1;
+
+
+ });
+
+
+
+
+
+
+
+
+
+ },
+
+
+ saveConfig : function()
+ {
+ var _this = this;
+ this.projects.forEach( function(p) {
+
+ if (!p.fn) {
+ // make the filename..
+ var t = new GLib.TimeVal();
+ GLib.get_current_time(t);
+ var str = '' + t.tv_sec + ':' + t.tv_usec;
+ Seed.print(str);
+ p.fn = GLib.compute_checksum_for_string(GLib.ChecksumType.MD5, str, str.length);
+ Seed.print(p.fn);
+
+ }
+ var s = p.toJSON();
+ File.write(_this.dirname + '/' + p.fn + '.json', s);
+
+
+ });
+
+
+
+
+ },
+ update : function(proj) {
+
+ //Seed.print(JSON.stringify(proj));
+ var found = false;
+ this.projects.forEach( function(p) {
+ if (proj == p) {
+ found = true;
+ return true;
+ }
+ });
+ if (found) {
+ this.fireEvent('changed', this);
+ return proj;
+ return;
+ }
+ var cls = imports.Project[proj.xtype][proj.xtype];
+ var pr = new cls(proj);
+ this.projects.push(pr );
+ this.fireEvent('changed', this);
+ return pr;
+
+
+ },
+
+ deleteProject : function (fn)
+ {
+ var newplist = [];
+ var _this = this;
+ this.projects.forEach(function(p) {
+ if (p.fn != fn) {
+ newplist.push(p);
+ return;
+ }
+ var file = _this.dirname + '/' + p.fn + '.json';
+ if (File.exists(file)) {
+ File.remove(file);
+ }
+
+ });
+ this.projects = newplist;
+ this.fireEvent('changed', this);
+ },
+
+
+ getByFn : function (fn) {
+ var ret = false;
+ this.projects.forEach(function(p) {
+ if (p.fn == fn) {
+ ret = p;
+ return true;
+ }
+ });
+ return ret;
+
+ },
+ getPalete: function(type) {
+ if (typeof(ProjectManager.palete[type]) != 'undefined') {
+ //print ("ALREADY GOT " + type);
+ return ProjectManager.palete[type];
+ }
+ var cls = imports.Palete[type][type];
+
+ ProjectManager.palete[type] = new cls();
+ print (typeof(ProjectManager.palete[type]));
+ return ProjectManager.palete[type];
+ }
+
+
+
+});
+
+
+
+
--- /dev/null
+///<script type="text/javascript">
+
+var Gio = imports.gi.Gio;
+var GLib = imports.gi.GLib;
+
+
+/**
+* @namespace Spawn
+*
+* Library to wrap GLib.spawn_async_with_pipes
+*
+* usage:
+*
+* Spawn = import.Spawn;
+*
+* simple version..
+* var output = Spawn.run({
+* cwd : '/home',
+* args : [ 'ls', '-l' ],
+* env : [], // optional
+* listeners : {
+ output : function (line) { Seed.print(line); },
+* stderr : function (line) {Seed.print("ERROR" + line); },
+* input : function() { return 'xxx' },
+* }
+* });
+*
+*
+*
+
+*
+*
+* CRITICAL - needs this change to gir in GLib-2.0.gir g_spawn_async_with_pipes
+* Fixed in Ubuntu 12.10
+ <parameter name="argv" transfer-ownership="none">
+ <array c:type="gchar**">
+ <type name="utf8"/>
+ </array>
+ </parameter>
+ <parameter name="envp" transfer-ownership="none" allow-none="1">
+ <array c:type="gchar**">
+ <type name="utf8"/>
+ </array>
+ </parameter>
+*
+* ALSO in GLib-2.0.gir
+
+<method name="read_line"
+ c:identifier="g_io_channel_read_line"
+ throws="1">
+ <return-value transfer-ownership="none">
+ <type name="IOStatus" c:type="GIOStatus"/>
+ </return-value>
+ <parameters>
+ <parameter name="str_return" transfer-ownership="full" direction="out">
+ <type name="utf8" c:type="gchar**"/>
+ </parameter>
+ <parameter name="length" transfer-ownership="none" direction="out">
+ <type name="gsize" c:type="gsize*"/>
+ </parameter>
+ <parameter name="terminator_pos" transfer-ownership="none" direction="out">
+ <type name="gsize" c:type="gsize*"/>
+ </parameter>
+ </parameters>
+ </method>
+*
+* run g-ir-compile -o /usr/lib/girepostitory-1.0/GLib-2.0.typelib GLib-2.0.gir
+*
+*
+*/
+
+
+/**
+ * @class Spawn
+ * @param cfg {Object} settings - see properties.
+ *
+ * @arg cwd {String} working directory. (defaults to home directory)
+ * @arg args {Array} arguments eg. [ 'ls', '-l' ]
+ * @arg listeners {Object} (optional) handlers for output, stderr, input
+ * stderr/output both receive output line as argument
+ * input should return any standard input
+ * finish recieves result as argument.
+ * @arg env {Array} enviroment eg. [ 'GITDIR=/home/test' ]
+ * @arg async {Boolean} (optional)return instantly, or wait for exit. (default no)
+ * @arg exceptions {Boolean} throw exception on failure (default no)
+ * @arg debug {Boolean} print out what's going on.. (default no)
+ *
+ */
+function Spawn(cfg) {
+ for(var i in cfg) {
+ this[i] = cfg[i];
+ }
+ // set defaults?
+ this.listeners = this.listeners || {};
+ this.cwd = this.cwd || GLib.get_home_dir();
+ if (!this.args || !this.args.length) {
+ throw "No arguments";
+ }
+
+}
+
+
+Spawn.prototype = {
+
+ ctx : false, // the mainloop ctx.
+ listeners : false,
+ async : false,
+ env : null,
+ cwd: false,
+ args: false,
+ exceptions : false,
+ debug : false,
+ /**
+ * @property output {String} resulting output
+ */
+ output : '',
+ /**
+ * @property stderr {String} resulting output from stderr
+ */
+ stderr : '',
+ /**
+ * @property result {Number} execution result.
+ */
+ result: 0,
+ /**
+ * @property pid {Number} pid of child process (of false if it's not running)
+ */
+ pid : false,
+ /**
+ * @property in_ch {GLib.IOChannel} input io channel
+ */
+ in_ch : false,
+ /**
+ * @property out_ch {GLib.IOChannel} output io channel
+ */
+ out_ch : false,
+ /**
+ * @property err_ch {GLib.IOChannel} stderr io channel
+ */
+ err_ch : false,
+ /**
+ *
+ * @method run
+ * Run the configured command.
+ * result is applied to object properties (eg. 'output' or 'stderr')
+ * @returns {Object} self.
+ */
+ run : function()
+ {
+
+ var _this = this;
+
+ var err_src = false;
+ var out_src = false;
+ var ret = {};
+
+ if (this.debug) {
+ print("cd " + this.cwd +";" + this.args.join(" "));
+ }
+
+ var gret = GLib.spawn_async_with_pipes(this.cwd, this.args, this.env,
+ GLib.SpawnFlags.DO_NOT_REAP_CHILD + GLib.SpawnFlags.SEARCH_PATH ,
+ null, null, ret);
+
+ var isSeed = true;
+ if (typeof(Seed) == 'undefined') {
+ ret = {
+ child_pid : gret[1],
+ standard_input : gret[2],
+ standard_output: gret[3],
+ standard_error: gret[4]
+ };
+ isSeed = false;
+ }
+
+ //print(JSON.stringify(gret));
+ this.pid = ret.child_pid;
+
+ if (this.debug) {
+ print("PID: " + this.pid);
+ }
+
+
+
+ GLib.child_watch_add(GLib.PRIORITY_DEFAULT, this.pid, function(pid, result) {
+ _this.result = result;
+ if (_this.debug) {
+ print("child_watch_add : result: " + result);
+ }
+ _this.read(_this.out_ch);
+ _this.read(_this.err_ch);
+
+
+ GLib.spawn_close_pid(_this.pid);
+ _this.pid = false;
+ if (_this.ctx) {
+ _this.ctx.quit();
+ }
+ tidyup();
+ //print("DONE TIDYUP");
+ if (_this.listeners.finish) {
+ _this.listeners.finish.call(this, _this.result);
+ }
+ });
+
+ function tidyup()
+ {
+ if (_this.pid) {
+ GLib.spawn_close_pid(_this.pid); // hopefully kills it..
+ _this.pid = false;
+ }
+ if (_this.in_ch) _this.in_ch.close();
+ if (_this.out_ch) _this.out_ch.close();
+ if (_this.err_ch) _this.err_ch.close();
+ // blank out channels
+ _this.in_ch = false;
+ _this.err_ch = false;
+ _this.out_ch = false;
+ // rmeove listeners !! important otherwise we kill the CPU
+ if (err_src !== false) GLib.source_remove(err_src);
+ if (out_src !== false) GLib.source_remove(out_src);
+ err_src = false;
+ out_src = false;
+
+ }
+
+
+ this.in_ch = new GLib.IOChannel.unix_new(ret.standard_input);
+ this.out_ch = new GLib.IOChannel.unix_new(ret.standard_output);
+ this.err_ch = new GLib.IOChannel.unix_new(ret.standard_error);
+
+ // make everything non-blocking!
+
+
+
+ // using NONBLOCKING only works if io_add_watch
+ //returns true/false in right conditions
+ this.in_ch.set_flags (GLib.IOFlags.NONBLOCK);
+ this.out_ch.set_flags (GLib.IOFlags.NONBLOCK);
+ this.err_ch.set_flags (GLib.IOFlags.NONBLOCK);
+
+
+
+ // add handlers for output and stderr.
+ out_src= GLib.io_add_watch(this.out_ch, GLib.PRIORITY_DEFAULT,
+ GLib.IOCondition.OUT + GLib.IOCondition.IN + GLib.IOCondition.PRI + GLib.IOCondition.HUP + GLib.IOCondition.ERR,
+ function() {
+
+ return _this.read(_this.out_ch);
+
+ }
+ );
+ err_src= GLib.io_add_watch(this.err_ch, GLib.PRIORITY_DEFAULT,
+ GLib.IOCondition.ERR + GLib.IOCondition.IN + GLib.IOCondition.PRI + GLib.IOCondition.OUT + GLib.IOCondition.HUP,
+ function()
+ {
+ return _this.read(_this.err_ch);
+
+ });
+
+
+
+ // call input..
+ if (this.pid !== false) {
+ // child can exit before 1we get this far..
+ if (this.listeners.input) {
+ print("Trying to call listeners");
+ try {
+ this.write(this.listeners.input.call(this));
+ // this probably needs to be a bit smarter...
+ //but... let's close input now..
+ this.in_ch.close();
+ _this.in_ch = false;
+
+
+
+
+
+ } catch (e) {
+ tidyup();
+ throw e;
+
+ }
+
+ }
+ }
+ // async - if running - return..
+ if (this.async && this.pid) {
+ return this;
+ }
+
+ // start mainloop if not async..
+
+ if (this.pid !== false) {
+ if (this.debug) {
+ print("starting main loop");
+ }
+
+ this.ctx = isSeed ? new GLib.MainLoop.c_new (null, false) : GLib.MainLoop.new (null, false);;
+ this.ctx.run(false); // wait fore exit?
+
+ //print("main_loop done!");
+ } else {
+ tidyup(); // tidyup get's called in main loop.
+ }
+
+ if (this.exceptions && this.result != 0) {
+ print(this.stderr);
+ print(this.output);
+ this.toString = function() { return this.stderr; };
+ throw this; // we throw self...
+ }
+
+ // finally throw, or return self..
+
+ return this;
+
+ },
+ /**
+ * write to stdin of process
+ * @arg str {String} string to write to stdin of process
+ * @returns GLib.IOStatus (0 == error, 1= NORMAL)
+ */
+ write : function(str) // write a line to
+ {
+ if (!this.in_ch) {
+ return 0; // input is closed
+ }
+ //print("write: " + str);
+ // NEEDS GIR FIX! for return value.. let's ignore for the time being..
+ //var ret = {};
+ //var res = this.in_ch.write_chars(str, str.length, ret);
+ var res = this.in_ch.write_chars(str, str.length);
+
+ //print("write_char retunred:" + JSON.stringify(res) + ' ' +JSON.stringify(ret) );
+
+ if (res != GLib.IOStatus.NORMAL) {
+ throw "Write failed";
+ }
+ //return ret.value;
+ return str.length;
+
+ },
+
+ /**
+ * read from pipe and call appropriate listerner and add to output or stderr string.
+ * @arg giochannel to read from.
+ * @returns none
+ */
+ read: function(ch)
+ {
+ var prop = ch == this.out_ch ? 'output' : 'stderr';
+ // print("prop: " + prop);
+ var _this = this;
+
+
+ //print(JSON.stringify(ch, null,4));
+ while (true) {
+
+ var x = {};
+ var status = ch.read_line( x);
+ // print('status: ' +JSON.stringify(status));
+ // print(JSON.stringify(x));
+ switch(status) {
+ case GLib.IOStatus.NORMAL:
+
+ //write(fn, x.str);
+ if (this.listeners[prop]) {
+ this.listeners[prop].call(this, x.str_return);
+ }
+ _this[prop] += x.str_return;
+ if (_this.debug) {
+ print(prop + ':' + x.str_return.replace(/\n/, ''));
+ }
+ if (this.async) {
+ try {
+ if (imports.gi.Gtk.events_pending()) {
+ imports.gi.Gtk.main_iteration();
+ }
+ } catch(e) {
+
+ }
+ }
+
+ //this.ctx.iteration(true);
+ continue;
+ case GLib.IOStatus.AGAIN:
+ //print("Should be called again.. waiting for more data..");
+ return true;
+ break;
+ case GLib.IOStatus.ERROR:
+ case GLib.IOStatus.EOF:
+ return false;
+ break;
+
+ }
+ break;
+ }
+
+ //print("RETURNING");
+ return false; // allow it to be called again..
+ }
+
+};
+/**
+ * @function run
+ *
+ * simple run a process - returns result, or throws stderr result...
+ * @param cfg {Object} see spawn
+ * @return {string} stdout output.
+ */
+function run(cfg) {
+ cfg.exceptions = true;
+ cfg.async = false;
+ var s = new Spawn(cfg);
+ var ret = s.run();
+ return s.output;
+}
+ /*
+// test
+try {
+ Seed.print(run({
+ args: ['ls', '/tmp'],
+ debug : true
+ }));
+} catch (e) { print(JSON.stringify(e)); }
+
+var secs = (new Date()).getSeconds()
+
+try {
+Seed.print(run({
+ args: ['/bin/touch', '/tmp/spawntest-' + secs ],
+ debug : true
+}));
+} catch (e) { print( 'Error: ' + JSON.stringify(e)); }
+
+
+ */
+
--- /dev/null
+/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+// usage:
+//imports['String.js'].load(String);
+if (imports) {
+ load = false; // declare global for gnome langs.
+}
+(function () {
+
+
+ var string = {
+
+ /** @scope String */
+
+ /**
+ * Escapes the passed string for ' and \
+ * @param {String} string The string to escape
+ * @return {String} The escaped string
+ * @static
+ */
+ escape : function(string) {
+ return string.replace(/('|\\)/g, "\\$1");
+ },
+
+ /**
+ * Pads the left side of a string with a specified character. This is especially useful
+ * for normalizing number and date strings. Example usage:
+ * <pre><code>
+ var s = String.leftPad('123', 5, '0');
+ // s now contains the string: '00123'
+ </code></pre>
+ * @param {String} string The original string
+ * @param {Number} size The total length of the output string
+ * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
+ * @return {String} The padded string
+ * @static
+ */
+ leftPad : function (val, size, ch) {
+ var result = new String(val);
+ if(ch === null || ch === undefined || ch === '') {
+ ch = " ";
+ }
+ while (result.length < size) {
+ result = ch + result;
+ }
+ return result;
+ },
+ /**
+ * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
+ * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
+ * <pre><code>
+ var cls = 'my-class', text = 'Some text';
+ var s = String.format('<div class="{0}">{1}</div>', cls, text);
+ // s now contains the string: '<div class="my-class">Some text</div>'
+ </code></pre>
+ * @p aram {String} string The tokenized string to be formatted
+ * @param {String} value1 The value to replace token {0}
+ * @param {String} value2 Etc...
+ * @return {String} The formatted string
+ * @static
+ */
+ format : function(format){
+ var args = Array.prototype.slice.call(arguments, 1);
+ return format.replace(/\{(\d+)\}/g, function(m, i){
+ return args[i];
+ });
+ },
+
+
+ /**
+ * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
+ * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
+ * <pre><code>
+ var cls = 'my-class', text = 'Some text';
+ var s = String.format('<div class="{0}">{1}</div>', cls, text);
+ // s now contains the string: '<div class="my-class">Some text</div>'
+ </code></pre>
+ * @param {String} string The tokenized string to be formatted
+ * @param {String} value1 The value to replace token {0}
+ * @param {String} value2 Etc...
+ * @return {String} The formatted string, all arguments will be htmlEncoded.
+ * @static
+ */
+ htmlFormat : function(format){
+ var args = Array.prototype.slice.call(arguments, 1);
+ return format.replace(/\{(\d+)\}/g, function(m, i){
+ return this.htmlEncode(args[i]);
+ });
+ },
+
+ /**
+ * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
+ * @param {String} value The string to encode
+ * @return {String} The encoded text
+ */
+ htmlEncode : function(value){
+ return !value ? value :
+ String(value).replace(/&/g, "&"
+ ).replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
+ }
+
+
+ };
+
+ /**
+ * Utility function that allows you to easily switch a string between two alternating values. The passed value
+ * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
+ * they are already different, the first value passed in is returned. Note that this method returns the new value
+ * but does not change the current string.
+ * <pre><code>
+ // alternate sort directions
+ sort = sort.toggle('ASC', 'DESC');
+
+ // instead of conditional logic:
+ sort = (sort == 'ASC' ? 'DESC' : 'ASC');
+ </code></pre>
+ * @param {String} value The value to compare to the current string
+ * @param {String} other The new value to use if the string already equals the first value passed in
+ * @return {String} The new value
+ */
+
+ var stringPrototype = {
+ toggle : function(value, other){
+ return this == value ? other : value;
+ },
+
+ trim : function (toTrim) {
+ var out = this.ltrim(toTrim);
+ out = out.rtrim(toTrim);
+ return out;
+ },
+
+ ltrim : function (toTrim) {
+ if (this.substr(0, toTrim.length) == toTrim) {
+ return this.slice(toTrim.length);
+ }
+
+ return this;
+ },
+
+ rtrim : function (toTrim) {
+ if (this.substr(this.length - toTrim.length) == toTrim) {
+ return this.slice(0, this.length - toTrim.length);
+ }
+
+ return this;
+ }
+
+ };
+
+
+
+ if (imports) {
+ load = function(ar) {
+ String = ar;
+ imports.lang.copyPropertiesNoOverwrite(string,ar);
+ imports.lang.copyPropertiesNoOverwrite(stringPrototype,ar.prototype);
+ };
+ } else {
+ // non imports version.
+ for(i in stringPrototype) {
+ if (!String.prototype[i]) {
+ String.prototype[i] = stringPrototype[i];
+ }
+ }
+ for(i in string) {
+ if (!String[i]) {
+ String[i] = string[i];
+ }
+ }
+ }
+})();
\ No newline at end of file
--- /dev/null
+//<script type="text/javascript">
+GIRepository = imports.gi.GIRepository;
+GObject = imports.gi.GObject;
+/**
+ * XObject
+ * Yet another attempt to create a usable object construction library for seed..
+ *
+ * Why is this useful?
+ * A) It turns rather messy code into a tree structure, making it easy to find code relating to
+ * an interface element
+ * B) In theory it should be gjs/Seed compatible..
+ * C) It provides getElementById style lookups for elements.
+ * D) It provides classic OO constructors for Javascript (extend/define)
+ * E) It does not modify any buildin prototypes..
+ *
+ * Extend this.. to use it's wonderful features..
+ *
+ * normal usage:
+ * XObject = imports.XObject.XObject;
+ *
+ * Xyz = new XObject({
+ * xtype: Gtk.Window,
+ * id : 'window',
+ * items : [
+ *
+ * ]
+ * });
+ * Xyz.init(); // create and show.
+ *
+ *
+ * use XObject.debug = 1 to turn on debugging
+ *
+ * If XObjectBase/[xns]/[xtype].js exists, it will use this to override properties..
+ *
+ *
+ * He's some questions.
+ * - should we have a special property to use as the constructor / gobject.properties rather
+ * than sending all basic types to this?
+ *
+ * @cfg xtype {String|Function} constructor or string.
+ * @cfg id {String} (optional) id for registry
+ * @cfg xns {String|Object} (optional) namespace eg. Gtk or 'Gtk' - used with xtype.
+ * @cfg items {Array} (optional) list of child elements which will be constructed.. using XObject
+ * @cfg listeners {Object} (optional) map Gobject signals to functions
+ * @cfg pack {Function|String|Array} (optional) how this object gets added to it's parent
+ * @cfg el {Object} (optional) premade GObject
+ *
+ */
+
+function XObject (cfg) {
+ // first apply cfg if set.
+ //print("new XOBJECT!!!");
+
+ //print ("XObject ctr");
+
+ this.config = {}; // used to initialize GObject
+
+ this.cfg = XObject.extend({}, cfg); // used to store original configuration.. for referencing..
+
+ // used by baseobject to create fake child elements on init..
+ if (cfg.el) {
+ this.el = cfg.el;
+ }
+
+ // we could use this to determine if
+ // we are actually inside a inherited class...
+ // as define() should actually set this up..
+
+ if (!this.constructor) {
+
+ this.constructor = XObject;
+ var base = XObject.baseXObject(cfg);
+ if (base) {
+ XObject.extend(this, base.prototype);
+ }
+
+ }
+
+ // copy down all elements into self..
+ // make an extra copy in this.config?? - which is the one used in the constructor later
+
+ for (var i in cfg) {
+ this[i] = cfg[i];
+ if (typeof(cfg[i]) == 'function') { // do we skip objects.
+ continue;
+ }
+ // these properties are not copied to cfg.
+ if ( i == 'pack' ||
+ i == 'items' ||
+ i == 'id' ||
+ i == 'xtype' ||
+ i == 'xdebug' ||
+ i == 'xns') {
+ continue;
+ }
+
+
+ this.config[i] = cfg[i];
+ }
+
+
+ this.items = this.items || [];
+
+
+ // pack can be false!
+ if (typeof(this.pack) == 'undefined') {
+
+ this.pack = [ 'add' ]
+ /*
+ var Gtk = imports.gi.Gtk;
+ switch (true) {
+ // any others!!
+ case (this.xtype == Gtk.MenuItem): this.pack = [ 'append' ]; break;
+
+ }
+ */
+
+ }
+
+ // interesting question should we call constructor on items here...
+ // as the real work is done in init anyway..
+ var _this= this;
+
+ var items = []
+ for(var i = 0; i < this.items.length;i++) {
+ items.push(this.items[i]);
+ }
+
+
+
+ this.items = [];
+ // create XObject for all the children.
+ for(var i = 0; i < items.length;i++) {
+
+ var base = XObject.baseXObject(items[i]);
+ base = base || XObject;
+ var item = (items[i].constructor == XObject) ? items[i] : new base(items[i]);
+ item.parent = _this;
+ _this.items.push(item);
+ //_this.addItem(i);
+ };
+
+
+}
+
+
+
+XObject.prototype = {
+ /**
+ * @property el {GObject} the Gtk / etc. element.
+ */
+ el : false,
+ /*
+ * @property items {Array} list of sub elements
+ */
+ /**
+ * @property parent {XObject} parent Element
+ */
+
+ /**
+ * @property config {Object} the construction configuration.
+ */
+ /**
+ * @method init
+ * Initializes the Element (el) hooks up all the listeners
+ * and packs the children.
+ * you can override this, in child objects, then
+ * do this to do thi initaliztion.
+ *
+ * XObject.prototype.init.call(this);
+ *
+ */
+ init : function(parent)
+ {
+
+ // var items = [];
+ //this.items.forEach(function(i) {
+ // items.push(i);
+ //});
+ // remove items.
+ this.listeners = this.listeners || {};
+ //this.items = [];
+
+ // do we need to call 'beforeInit here?'
+
+ // handle include?
+ //if ((this.xtype == 'Include')) {
+ // o = this.pre_registry[cls];
+ //}
+ var isSeed = typeof(Seed) != 'undefined';
+
+ // xtype= Gtk.Menu ?? what about c_new stuff?
+ XObject.log("init: ID:"+ this.id +" typeof(xtype): " + typeof(this.xtype));
+ if (!this.el && typeof(this.xtype) == 'function') {
+ XObject.log("func?" + XObject.keys(this.config).join(','));
+ this.el = this.xtype(this.config);
+
+ }
+ if (!this.el && typeof(this.xtype) == 'object') {
+ XObject.log("obj?" + XObject.keys(this.config).join(','));
+ this.el = new (this.xtype)(this.config);
+
+ }
+ //print(this.el);
+ if (!this.el && this.xns) {
+
+ var NS = imports.gi[this.xns];
+ if (!NS) {
+ XObject.error('Invalid xns: ' + this.xns, true);
+ }
+ constructor = NS[this.xtype];
+ if (!constructor) {
+ XObject.error('Invalid xtype: ' + this.xns + '.' + this.xtype);
+ }
+ this.el = isSeed ? new constructor(this.config) : new constructor();
+
+ }
+ XObject.log("init: ID:"+ this.id +" typeof(el):" + this.el);
+
+ // always overlay props..
+ // check for 'write' on object..
+ /*
+ if (typeof(XObject.writeablePropsCache[this.xtype.type]) == 'undefined') {
+
+ var gi = GIRepository.IRepository.get_default();
+ var ty = gi.find_by_gtype(this.xtype.type);
+ var write = [];
+ for (var i =0; i < GIRepository.object_info_get_n_properties(ty);i++) {
+ var p = GIRepository.object_info_get_property(ty,i);
+ if (GIRepository.property_info_get_flags(p) & 2) {
+ write.push(GIRepository.base_info_get_name(p));
+ }
+ }
+ XObject.writeablePropsCache[this.xtype.type] = write;
+ print(write.join(", "));
+ }
+
+ */
+
+
+ for (var i in this.config) {
+ if (i == 'type') { // problem with Gtk.Window... - not decided on a better way to handle this.
+ continue;
+ }
+ if (i == 'buttons') { // problem with Gtk.MessageDialog..
+ continue;
+ }
+ if (i[0] == '.') { // parent? -
+ continue;
+ }
+ this.el[i] = this.config[i];
+ }
+
+ // register it!
+ //if (o.xnsid && o.id) {
+ // XObject.registry = XObject.registry || { };
+ // XObject.registry[o.xnsid] = XObject.registry[o.xnsid] || {};
+ // XObject.registry[o.xnsid][o.id] = this;
+ //}
+
+ var type = this.xtype.type ? GObject.type_name(this.xtype.type) : '';
+ XObject.log("add children to " + type);
+
+ var _this=this;
+ for (var i = 0; i < this.items.length;i++) {
+ _this.addItem(this.items[i],i);
+ }
+
+
+ for (var i in this.listeners) {
+ this.addListener(i, this.listeners[i]);
+ }
+
+ this.init = XObject.emptyFn;
+
+ // delete this.listeners ?
+ // do again so child props work!
+
+ // do we need to call 'init here?'
+ },
+
+
+ /**
+ * Adds an item to the object using a new XObject
+ * uses pack property to determine how to add it.
+ * @arg cfg {Object} same as XObject constructor.
+ */
+ addItem : function(item, pos)
+ {
+
+ if (typeof(item) == 'undefined') {
+ XObject.error("Invalid Item added to this!");
+ imports.console.dump(this.cfg);
+ Seed.quit();
+ }
+ // what about extended items!?!?!?
+
+ item.init(this);
+ //print("CTR:PROTO:" + ( item.id ? item.id : '??'));
+ // print("addItem - call init [" + item.pack.join(',') + ']');
+ if (!item.el) {
+ XObject.error("NO EL!");
+ imports.console.dump(item);
+ Seed.quit();
+ }
+ XObject.log(XObject.type(this.xtype) + ":pack=" + item.pack);
+
+ if (item.pack===false) { // no packing.. various items have this ..
+ return;
+ }
+
+ if (typeof(item.pack) == 'function') { // pack is a function..
+ // parent, child
+ item.pack.apply(item, [ this , item ]);
+ item.parent = this;
+ return;
+ }
+
+ // pack = 'add,x,y'
+ var args = [];
+ var pack_m = false;
+ if (typeof(item.pack) == 'string') {
+
+ item.pack.split(',').forEach(function(e, i) {
+
+ if (e == 'false') { args.push( false); return; }
+ if (e == 'true') { args.push( true); return; }
+ if (!isNaN(parseInt(e))) { args.push( parseInt(e)); return; }
+ args.push(e);
+ });
+ //print(args.join(","));
+
+ pack_m = args.shift();
+ } else {
+ pack_m = item.pack.shift();
+ args = item.pack;
+ }
+
+ // handle error.
+ if (pack_m && typeof(this.el[pack_m]) == 'undefined') {
+
+ throw {
+ name: "ArgumentError",
+ message : 'pack method not available : ' + this.id + " : " + this.xtype + '.' + pack_m + " ADDING " + item.el
+
+ }
+
+ return;
+ }
+
+
+ // finally call the pack method
+ //Seed.print('Pack ' + this.el + '.'+ pack_m + '(' + item.el + ')');
+
+ args.unshift(item.el);
+
+
+
+
+
+ XObject.log(pack_m + '[' + args.join(',') +']');
+ //Seed.print('args: ' + args.length);
+ if (pack_m) {
+ this.el[pack_m].apply(this.el, args);
+ }
+
+
+
+ },
+ /**
+ * Connects a method to a signal. (gjs/Seed aware)
+ *
+ * @param {String} sig name of signal
+ * @param {Function} fn handler.
+ */
+ addListener : function(sig, fn)
+ {
+
+ XObject.log("Add signal " + sig);
+ fn.id= sig;
+ var _li = XObject.createDelegate(fn,this);
+ // private listeners that are not copied to GTk.
+
+ if (typeof(Seed) != 'undefined') {
+ // Seed.print(typeof(_li));
+ this.el.signal[sig].connect(_li);
+ } else {
+ this.el.connect( sig, _li);
+ }
+
+
+ },
+ /**
+ * @method get
+ * Finds an object in the child elements using xid of object.
+ * prefix with '.' to look up the tree..
+ * prefix with multiple '..' to look further up..
+ * prefix with '/' to look from the top, eg. '^LeftTree.model'
+ *
+ * @param {String} name name of signal
+ * @return {XObject|false} the object if found.
+ */
+ get : function(xid)
+ {
+ XObject.log("SEARCH FOR " + xid + " in " + this.id);
+ return this.getBySearch(xid);
+ },
+ getBySearch : function(xid) {
+
+ var ret= false;
+ var oid = '' + xid;
+ if (!xid.length) {
+ throw {
+ name: "ArgumentError",
+ message : "ID not found : empty id"
+ }
+ }
+
+ if (xid[0] == '.') {
+ return this.parent.getBySearch(xid.substring(1));
+ }
+ if (xid[0] == '/') {
+
+ if (typeof(XObject.cache[xid]) != 'undefined') {
+ return XObject.cache[xid];
+ }
+ if (xid.indexOf('.') > -1) {
+
+ var child = xid.split('.');
+ var nxid = child.shift();
+
+ child = child.join('.');
+ if (typeof(XObject.cache[nxid]) != 'undefined') {
+ return XObject.cache[nxid].getBySearch(child);
+ }
+
+
+ }
+ var e = this;
+ while (e.parent) {
+ e = e.parent;
+ }
+
+ try {
+ ret = e.getBySearch(xid.substring(1));
+ } catch (ex) { }
+
+ if (!ret) {
+ throw {
+ name: "ArgumentError",
+ message : "ID not found : " + oid
+ }
+ }
+ XObject.cache[xid] = ret;
+ return XObject.cache[xid];
+ }
+ var child = false;
+
+ if (xid.indexOf('.') > -1) {
+ child = xid.split('.');
+ xid = child.shift();
+
+ child = child.join('.');
+
+ }
+ if (xid == this.id) {
+ try {
+ return child === false ? this : this.getBySearch(child);
+ } catch (ex) {
+ throw {
+ name: "ArgumentError",
+ message : "ID not found : " + oid
+ }
+ }
+
+ }
+
+
+ this.items.forEach(function(ch) {
+ if (ret) {
+ return;
+ }
+ if (ch.id == xid) {
+ ret = ch;
+ }
+ })
+ if (ret) {
+ try {
+ return child === false ? ret : ret.getBySearch(child);
+ } catch (ex) {
+ throw {
+ name: "ArgumentError",
+ message : "ID not found : " + oid
+ }
+ }
+
+ }
+ // iterate children.
+ var _this = this;
+ this.items.forEach(function(ch) {
+ if (ret) {
+ return;
+ }
+ if (!ch.get) {
+ XObject.error("invalid item...");
+ imports.console.dump(_this);
+ Seed.quit();
+ }
+ try {
+ ret = ch.getBySearch(xid);
+ } catch (ex) { }
+
+
+ });
+ if (!ret) {
+ throw {
+ name: "ArgumentError",
+ message : "ID not found : " + oid
+ }
+ }
+ try {
+ return child === false ? ret : ret.getBySearch(child);
+ } catch (ex) {
+ throw {
+ name: "ArgumentError",
+ message : "ID not found : " + oid
+ }
+ }
+ }
+
+
+}
+
+
+/**
+ * Copies all the properties of config to obj.
+ *
+ * Pretty much the same as JQuery/Prototype.. or Roo.apply
+ * @param {Object} obj The receiver of the properties
+ * @param {Object} config The source of the properties
+ * @param {Object} defaults A different object that will also be applied for default values
+ * @return {Object} returns obj
+ * @member XObject extend
+ */
+
+
+XObject.extend = function(o, c, defaults){
+ if(defaults){
+ // no "this" reference for friendly out of scope calls
+ XObject.extend(o, defaults);
+ }
+ if(o && c && typeof c == 'object'){
+ for(var p in c){
+ o[p] = c[p];
+ }
+ }
+ return o;
+};
+
+XObject.extend(XObject,
+{
+
+ /**
+ * @property {Boolean} debug XObject debugging. - set to true to debug.
+ *
+ */
+ debug : true,
+ /**
+ * @property {Object} cache - cache of object ids
+ *
+ */
+ cache: { },
+ /**
+ * Empty function
+ *
+ */
+ emptyFn : function () { },
+
+
+
+ /**
+ * Debug Logging
+ * @param {String|Object} output String to print.
+ */
+ log : function(output)
+ {
+ if (!this.debug) {
+ return;
+ }
+ print("LOG:" + output);
+ },
+
+ /**
+ * Error Logging
+ * @param {String|Object} output String to print.
+ */
+ error : function(output)
+ {
+ print("ERROR: " + output);
+ },
+ /**
+ * fatal error
+ * @param {String|Object} output String to print.
+ */
+ fatal : function(output)
+ {
+
+ throw {
+ name: "ArgumentError",
+ message : output
+
+ }
+ },
+
+ /**
+ * Copies all the properties of config to obj, if the do not exist.
+ * @param {Object} obj The receiver of the properties
+ * @param {Object} config The source of the properties
+ * @return {Object} returns obj
+ * @member Object extendIf
+ */
+
+
+ extendIf : function(o, c)
+ {
+
+ if(!o || !c || typeof c != 'object'){
+ return o;
+ }
+ for(var p in c){
+ if (typeof(o[p]) != 'undefined') {
+ continue;
+ }
+ o[p] = c[p];
+ }
+ return o;
+ },
+
+ /**
+ * Deep clone..
+ * @param {Object} o the object to clone..
+ * @return {Object} returns clone of object
+ * @member Object xclone
+ */
+ xclone : function(o)
+ {
+ var cp = function(e) {
+
+ if (typeof(e) != 'object') {
+ return e;
+ }
+
+ if (typeof(e) == 'object' && Array.isArray(e)) {
+ var ar = [];
+ for (var i =0; i < e.length;i++) {
+ ar.push(cp(e[i]));
+ }
+ return ar;
+ }
+
+ return XObject.xclone(e);
+
+ };
+
+ var r = {};
+ for(var p in o){
+ //print (p + ': ' + typeof(o[p]));
+ r[p] = cp(o[p])
+ }
+ return r;
+ },
+
+
+ /**
+ * Extends one class with another class and optionally overrides members with the passed literal. This class
+ * also adds the function "override()" to the class that can be used to override
+ * members on an instance.
+ *
+ * usage:
+ * MyObject = Object.define(
+ * function(...) {
+ * ....
+ * },
+ * parentClass, // or Object
+ * {
+ * ... methods and properties.
+ * }
+ * });
+ * @param {Function} constructor The class inheriting the functionality
+ * @param {Object} superclass The class being extended
+ * @param {Object} overrides (optional) A literal with members
+ * @return {Function} constructor (eg. class
+ * @method define
+ */
+ define : function()
+ {
+ // inline overrides
+ var io = function(o){
+ for(var m in o){
+ this[m] = o[m];
+ }
+ };
+ return function(constructor, parentClass, overrides) {
+ if (typeof(parentClass) == 'undefined') {
+ XObject.error("XObject.define: Missing parentClass: when applying: " );
+ XObject.error(new String(constructor));
+ Seed.quit();
+ }
+ if (typeof(parentClass.prototype) == 'undefined') {
+ XObject.error("Missing protype: when applying: " );
+ XObject.error(new String(constructor));
+ XObject.error(new String(parentClass));
+ Seed.quit();
+ }
+ var F = function(){};
+ var sbp;
+ var spp = parentClass.prototype;
+
+ F.prototype = spp;
+ sbp = constructor.prototype = new F();
+ sbp.constructor=constructor;
+ constructor.superclass=spp;
+
+ // extends Object.
+ if(spp.constructor == Object.prototype.constructor){
+ spp.constructor=parentClass;
+ }
+
+ constructor.override = function(o){
+ Object.extend(constructor.prototype, o);
+ };
+ sbp.override = io;
+ XObject.extend(constructor.prototype, overrides);
+ return constructor;
+ };
+ }(),
+
+
+ /**
+ * returns a list of keys of the object.
+ * @param {Object} obj object to inspect
+ * @return {Array} returns list of kyes
+ * @member XObject keys
+ */
+ keys : function(o)
+ {
+ var ret = [];
+ for(var i in o) {
+ ret.push(i);
+ }
+ return ret;
+ },
+ /**
+ * return the Gobject name of a constructor - does not appear to work on structs..
+ * @param {Object} gobject ctr
+ * @return {String} returns name
+ * @member XObject type
+ */
+ type : function(o)
+ {
+ if (typeof(o) == 'object') {
+ return GObject.type_name(o.type);
+ // print("GNAME:" +gname + " GTYPE:"+cfg.xtype.type);
+ }
+ return 'unknown';
+ },
+ /**
+ * return the XObjectBase class for a cfg (which includes an xtype)
+ * @param {Object} configuration.
+ * @return {function} constructor
+ * @member XObject baseXObject
+ */
+ baseXObject : function(cfg)
+ {
+ try {
+ // loocks for XObject/Gtk/TreeView.js [ TreeView = { .... } ]
+ // xns is not a string!!!?
+ var gname = false;
+ if (typeof(cfg.xtype) == 'object') {
+ gname = XObject.type(cfg.xtype);
+
+ }
+ if (typeof(cfg.xtype) == 'string') {
+ gname = cfg.xtype;
+ }
+
+ XObject.log("TRYING BASE OBJECT : " + gname);
+ // in the situation where we have been called and there is a base object
+ // defining the behavior..
+ // then we should copy the prototypes from the base object into this..
+
+ // see if file exists???
+
+ var base = gname ? imports.XObjectBase[gname][gname] : false;
+ return base;
+
+ } catch (e) {
+ // if debug?
+ XObject.log("error finding " + gname + " - " + e.toString());
+ return false;
+ }
+
+
+ },
+
+ /**
+ * @member XObject createDelegate
+ * creates a delage metdhod
+ * @param {Function} method to wrap
+ * @param {Object} scope
+ * @param {Array} args to add
+ * @param {Boolean|Number} append arguments or replace after N arguments.
+ * @return {Function} returns the delegate
+ */
+
+ createDelegate : function(method, obj, args, appendArgs){
+
+ return function() {
+ XObject.log("CALL: " + obj.id + ':'+ method.id);
+
+ var callArgs = args || arguments;
+ if(appendArgs === true){
+ callArgs = Array.prototype.slice.call(arguments, 0);
+ callArgs = callArgs.concat(args);
+ }else if(typeof appendArgs == "number"){
+ callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
+ var applyArgs = [appendArgs, 0].concat(args); // create method call params
+ Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
+ }
+ return method.apply(obj || window, callArgs);
+ };
+ }
+
+});
--- /dev/null
+//<script type="text/javascript">
+
+
+var MODULE = { isBuilder : true };
+// BC
+var _this = MODULE;
+
+// the apprenderer.
+Builder = {
+
+ scriptTag : false,
+
+ id : 1,
+
+ render : function(data, clsname)
+ {
+
+ // console.log(data);
+ console.log(clsname);
+ // for debugging
+ // console.log(data); return;
+ //Roo.log(data);
+ //Roo.log(data);
+ // This would be alot simpler if we just use the XComponent code...
+ // data should now be dialog or xcomponent..
+ // only snag here is that we do not know the name currently..
+ //Roo.log(clsname);
+ var ix = '_src_' + this.id++;
+ // should replace module name with Builder._src_{id}
+ data = data.replace(clsname, 'Builder.' + ix);
+ // next.. we need to ensure that parent is set correctly..
+ // done by sender... otherwise building becomes difficult..
+ //data += "\n" + 'Builder.' + ix + ".parent = '#renderel';\n";
+ console.log(data);
+ //Roo.log(data);return;
+ //Roo.log(data);
+ if (this.scriptTag) {
+ document.body.removeChild(this.scriptTag);
+ this.scriptTag = false;
+ }
+
+ this.scriptTag = document.body.appendChild(document.createElement('script'));
+ this.scriptTag.setAttribute('type','text/javascript');
+
+ this.id++;
+ this.scriptTag.appendChild(
+ document.createTextNode(
+ data
+ ));
+
+
+ //Roo.log(this.tree);
+ MODULE = { isBuilder : true };
+ _this = MODULE;
+ if (!Builder.click) {
+ Builder.click= Roo.get(document.body).on('click', this.onclick, this);
+ }
+ Roo.log('Builder.'+ ix);
+ Roo.XComponent.build();
+ return;
+
+ return;
+ var wait_for_tree = function() {
+
+ Builder.tree = Builder[ix];
+ if (!Builder.tree) {
+ Roo.log("Wating for tree : " + ix);
+ wait_for_tree.defer(100);
+ return;
+ }
+ Builder.redraw(false);
+ }
+ wait_for_tree.defer(100);
+ },
+
+
+
+ tree : {},
+ renderObj : { isBuilder : true },
+ dialogroot : false,
+
+ redrawClear : function(isAuto)
+ {
+ this.renderObj = { isBuilder : true };
+
+ this.scroll = {
+ top:0,
+ left:0
+ };
+
+
+
+ //if (this.panelroot) {
+ // this.scroll = this.panelroot.el.getScroll();
+ // this.layout.remove('center', this.panelroot);
+ // this.panelroot = false;
+ //}
+ if (this.dialogroot) {
+ this.dialogroot.remove();
+ this.dialogroot = false;
+ }
+ if (this.layoutbase) {
+ //console.log(Builder.dump(this.layoutbase.el));
+
+
+ try {
+ var pan = this.layoutbase.getRegion('center').getPanel(0);
+ if (pan) {
+ this.layoutbase.remove('center', pan);
+ }
+
+
+ } catch( e) {
+ console.log(e);
+ console.log(JSON.stringify(e));
+ // reload!!?
+ }
+
+
+
+ //this.layoutbase= false;
+ }
+
+
+ },
+
+
+ redraw: function(isAuto)
+ {
+
+ // top level is not relivant
+ this.redrawClear(isAuto);
+
+
+ var cfg = this.tree;
+ //console.log(this.dump(cfg));
+ if (!cfg) {
+ return;
+ }
+
+
+ this.munge(cfg);
+ this.cfg = cfg;
+ //console.log(this.dump(cfg));
+ // we draw either a dialog or a tab..
+
+ if (cfg.xtype == 'LayoutDialog') {
+
+ cfg.modal = false;
+ //var xy = Pman.Tab.BuilderPanel.panel.el.getXY();
+ //cfg.items[0].x = xy[0];
+ //cfg.items[0].y = xy[1];
+ //cfg.items[0].constraintoviewport = false;
+
+ this.dialogroot = Roo.get( document.body).createChild({
+ id : cfg.id
+ });
+
+
+ MODULE.dialog = new Roo[cfg.xtype](this.dialogroot, cfg);
+ //this.dialog.el.on('click', this.panelClick, this);
+ MODULE.dialog.show();
+ return;
+
+ }
+
+ // otherwise we are creating a layout area on the document..
+
+
+ // handles
+ // contentpanel, nestedlayoutpanel, contentpanel.. etc.
+ // force center region..
+ cfg.region = 'center';
+ cfg.background = false;
+ if (!this.layoutbase) {
+
+ this.layoutbase = new Ext.BorderLayout(document.body, {
+
+ center: {
+ titlebar: false,
+ autoScroll:false,
+ closeOnTab: true,
+ tabPosition: 'top',
+ //resizeTabs: true,
+ alwaysShowTabs: true,
+ minTabWidth: 140
+ }
+ });
+ }
+ try {
+ console.log("ADDING CFG");
+ console.log(cfg)
+ this.layoutbase.addxtype( cfg );
+ } catch (e) {
+ console.log("GOT ERROR? - saved in Builder.lastError");
+ Builder.lastError = e;
+ console.log(e);
+ console.log(typeof(e));
+
+ console.log(this.dump(e));
+ console.trace();
+ }
+
+
+ },
+
+
+ munge :function (cfg, isListener)
+ {
+ var xitems = false;
+ //cfg.cls = cfg.cls || '';
+ //cfg.cls += ' ' + cfg.id;
+ if (!cfg.id) {
+ this.dump(cfg);
+ }
+
+ //console.log(cfg.xtype + ': ' + cfg.id);
+
+ if (cfg.items) {
+ xitems = cfg.items;
+ delete cfg.items;
+ }
+ if (typeof(cfg.background) != 'undefined') {
+ cfg.background = false;
+ }
+
+ var xtype = (cfg['|xns'] || '') + '.' + (cfg.xtype || '');
+
+ for(var p in cfg){
+ // key is not string?!?!?!!?
+
+ if (typeof(p) != 'string') {
+ continue;
+ }
+
+ if (typeof(cfg[p]) == 'object') { // listeners!!!
+ this.munge(cfg[p], p == 'listeners');
+ continue;
+ }
+ // SPECIAL - PIPE
+ if (p.charAt(0) == '|' || isListener) {
+
+ if (!cfg[p].length) {
+ delete cfg[p];
+ continue;
+ }
+ var pp = p.charAt(0) == '|' ? p.substring(1) : p;
+ try {
+
+
+ var _tmp = false;
+
+ /** eval:var:MOUDULE **/
+ /** eval:var:_this **/
+ /** eval:var:_tmp **/
+ // stupid IE can not return objects evaluated..
+ // console.log('_tmp =(' + cfg[p] + ')');
+ eval('_tmp =(' + cfg[p] + ')');
+ cfg[pp] = _tmp;
+
+ //if (typeof(_tmp) == 'undefined') {
+ // alert(cfg[p]);
+ // }
+
+ } catch(e) {
+ console.log('Error evaluating: ' + cfg[p] + "\r\n" + JSON.stringify(e));
+ };
+ if (pp != p) {
+ delete cfg[p];
+ }
+
+
+
+ continue;
+ }
+ // skip '*'
+ if ((p.charAt(0) == '*') || (p.charAt(0) == '+')) {
+ delete cfg[p];
+ continue;
+ }
+ // normal..
+
+ }
+
+ if (cfg.xtype && cfg.xtype.match(/^Roo\./) && !cfg.xns) {
+ // xtype contains full path..
+ var bits = cfg.xtype.split('.');
+ bits.shift(); // remove roo..
+ cfg.xtype = bits.pop(); // get the last bit..
+ cfg.xns = Roo;
+ while (bits.length) {
+ cfg.xns = cfg.xns[bits.shift()];
+ }
+
+ }
+ if (cfg.xtype) {
+ if (!cfg.xns || typeof(cfg.xns[cfg.xtype]) == 'undefined') {
+ throw "Invalid Xtype " + cfg.xtype + ' on ' + cfg.xtreepath;
+ }
+ }
+ if (!isListener) {
+ cfg.listeners = cfg.listeners || {};
+ }
+ // we can overlay some event handlers here..
+
+
+ //console.log('xtype' + xtype)
+ switch(xtype) {
+ case 'Roo.LayoutDialog':
+ cfg.listeners.resize = function(dlg, w,h)
+ {
+ console.log('{ "id" : "' + dlg.id + '", "set" : "width", "value": ' + w + '}');
+ console.log('{ "id" : "' + dlg.id + '", "set" : "height", "value": ' + h + '}');
+ }
+ break;
+ }
+
+
+
+
+
+ // now for all the children.. (items)
+ if (xitems === false) {
+
+ return;
+ }
+ cfg.items = [];
+ for (var i = 0; i < xitems.length; i++) {
+ // if +builderhide set !!!! drop it!!
+
+
+ var xi = xitems[i];
+ if (typeof(xi['*prop']) != 'undefined') {
+ //console.log('adding prop:' + xi['*prop']);
+
+ var pr = xi['*prop'];
+ this.munge(xi);
+ // if prop is an array - then it's items are really the value..
+ if (pr.match(/\[\]$/)) {
+ //console.log('adding array?:' + pr);
+ pr = pr.replace(/\[\]$/, '');
+ cfg[pr] = cfg[pr] || [];
+ cfg[pr].push(xi);
+ continue;
+ }
+
+
+ if (xi.xtype && xi.xtype == 'Array') {
+ cfg[pr] = xi.items;
+ } else {
+ //console.log('setting property:' + pr);
+ cfg[pr] = xi;
+ }
+
+
+ continue;
+ }
+ this.munge(xi);
+ cfg.items.push(xi);
+ }
+
+ if (cfg.items.length == 0) {
+ delete cfg.items;
+ }
+ console.log(cfg);
+
+
+ },
+
+
+
+ cloneConfig : function(config) {
+ if (!config) { return null; }
+ var newConfig = {};
+ for (var i in config) {
+ if (typeof config[i] == 'object') {
+ newConfig[i] = this.cloneConfig(config[i]);
+ } else if (typeof config[i] != 'function') {
+ newConfig[i] = config[i];
+ }
+ }
+ return newConfig;
+ },
+ dump : function (arr,level) {
+ var dumped_text = "";
+ if(!level) level = 0;
+ if (level > 3) {
+ return '... TO DEEP ...';
+ }
+ //The padding given at the beginning of the line.
+ var level_padding = "";
+ for(var j=0;j<level+1;j++) level_padding += " ";
+
+ if(typeof(arr) == 'object') { //Array/Hashes/Objects
+ for(var item in arr) {
+
+ var value = arr[item];
+ if (item == 'xns') {
+ continue;
+ }
+ if(typeof(value) == 'function') { //If it is an array,
+ // fake dump...
+ dumped_text += level_padding + "'" + item + "' : function() { ... },\n";
+ continue;
+ }
+ if(typeof(value) == 'object') { //If it is an array,
+ dumped_text += level_padding + "'" + item + "': {\n";
+ dumped_text += this.dump(value,level+1);
+ dumped_text += level_padding + "}\n";
+ continue;
+ }
+ dumped_text += level_padding + "'" + item + "' : \"" + value + "\"\n";
+
+ }
+ } else { //Stings/Chars/Numbers etc.
+ dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
+ }
+ return dumped_text;
+ },
+ findNode : function(ftg , method) {
+ if (!ftg) {
+ return; false
+ }
+ // console.log(ftg.id);
+ if (ftg.id && typeof(ftg.id) == 'string' && ftg.id.match(/builder-/)) {
+ var nid = ftg.id.replace('builder-', '').replace('x-form-el-', '');
+ this[method]( nid );
+ return true;
+ }
+ // needs fixing..
+ if (ftg.dom.className.match(/[0-9]+/)) {
+ //console.log(ftg.dom.className);
+ var cmat = ftg.dom.className.match(/x-grid-hd-builder-(form-gen-[0-9:]+)/);
+ if (cmat) {
+ this[method]( cmat[1] );
+ return true;
+ }
+ }
+
+
+
+
+ return false;
+ },
+
+ overPos: function(x,y)
+ {
+
+ var el = document.elementFromPoint(x,y);
+ // //console.log(el.id);
+ // console.log(document.body.innerHTML);
+ this.hover( {
+ getTarget : function () {
+ return el;
+ },
+ stopEvent : function() {
+
+ }
+ });
+
+
+ },
+ onclick: function(e) {
+ var tg = Roo.get(e.getTarget());
+ if (!tg) {
+ //console.log('no target');
+ return;
+ }
+
+ if (this.findNode(tg,'logClick')) {
+ return;
+ }
+ var dp = Roo.get(tg.up(''));
+ if (dp && this.findNode(dp,'logClick')) {
+ return;
+ }
+
+ var ns = Roo.get(tg.getNextSibling());
+ if (ns && this.findNode(ns,'logClick')) {
+
+ return;
+ }
+ if (ns && ns.down('') && this.findNode(Roo.get(ns.down('')) ,'logClick') ) {
+ return;
+ }
+
+ for(var i =0; i < 5; i++) {
+ tg = Roo.get(tg.up(''));
+ if (!tg) {
+ //console.log('no parent' + i);
+ return;
+ }
+ if (tg && this.findNode(tg,'logClick')) {
+ return;
+ }
+ }
+ //console.log('no target in parents');
+
+ },
+ logClick : function(id)
+ {
+ var bid = id.length ? 'builder-' + id : '';
+ console.log('{ "id" : "' + bid + '"}');
+ },
+
+
+ hover : function(e) {
+
+
+ var tg = Roo.get(e.getTarget());
+ if (!tg) {
+ //console.log('no target');
+ this.logMove('');
+ return;
+ }
+
+ if (this.findNode(tg,'logMove')) {
+ e.stopEvent();
+ return;
+ }
+ var dp = Roo.get(tg.up(''));
+ if (dp && this.findNode(dp,'logMove')) {
+ e.stopEvent();
+ return;
+ }
+
+ var ns = Roo.get(tg.getNextSibling());
+ if (ns && this.findNode(ns,'logMove')) {
+ e.stopEvent();
+ return;
+ }
+ if (ns && ns.down('') && this.findNode(Roo.get(ns.down('')) ,'logMove' )) {
+ e.stopEvent();
+ return;
+ }
+
+ for(var i =0; i < 5; i++) {
+ tg = Roo.get(tg.up(''));
+ if (!tg) {
+ //console.log('no parent' + i);
+ this.logMove('');
+ return;
+ }
+ if (tg && this.findNode(tg,'logMove')) {
+ e.stopEvent();
+ return;
+ }
+ }
+ //console.log('no target in parents');
+ this.logMove('');
+ },
+ logMove : function (id) {
+ //console.log("LOGMOVE: " + id);
+
+ if (this.lastID === id) {
+ return;
+ }
+ id = ''+ id;
+ var bid = id.length ? 'builder-' + id : '';
+ console.log('{ "hover-node" : "' + bid + '"}');
+ this.lastID = id;
+ },
+ clearBootstrap : function()
+ {
+ // if the page is not bootstrap
+
+ if ( typeof(BuilderUseBootstrap) != 'undefined' ) {
+ Roo.log("it's boostrap - BuilderUseBootstrap is defined ");
+ // it's bootstrap - probably remove roo's css..
+ return;
+ }
+ Roo.log("remove css = BuilderUseBootstrap is not defined");
+ var rem = [];
+ var ar = document.getElementsByTagName('link');
+ for (var i = 0; i < ar.length;i++) {
+ var l = ar[i];
+ Roo.log(l.getAttribute('href'));
+ if (l.getAttribute('href').match(/bootstrap/)) {
+ rem.push(l);
+
+
+ }
+ //code
+ }
+ Roo.each(rem, function(l) { l.parentNode.removeChild(l);});
+ },
+
+ applyFlexy: function(tree)
+ {
+ if (typeof(tree['flexy:foreach']) != 'undefined') {
+ //Roo.log("add flexy:foreach");
+ tree.el.attr('flexy:foreach', tree['flexy:foreach']);
+ }
+ if (typeof(tree['flexy:if']) != 'undefined') {
+ //Roo.log("add flexy:if");
+ tree.el.attr('flexy:if', tree['flexy:if']);
+ }
+ if (typeof(tree['flexy:include']) != 'undefined') {
+ //Roo.log("add flexy:if");
+ tree.el.attr('flexy:include', tree['flexy:include']);
+ }
+
+ if (typeof(tree['xtype-bootstrap']) != 'undefined') {
+ //Roo.log("add flexy:if");
+ tree.el.attr('xtype', tree['xtype-bootstrap']);
+ }
+
+
+ if (!tree.items || !tree.items.length) { return; }
+
+ for (var i = 0; i < tree.items.length; i++){
+ this.applyFlexy(tree.items[i]);
+ }
+ }
+
+
+
+};
+Roo.onReady(function() { Builder.clearBootstrap(); });
+Roo.XComponent.on('buildcomplete', function() {
+ Roo.log("xcomponent built!");
+
+ Builder.applyFlexy(Roo.XComponent.modules[0].el);
+});
\ No newline at end of file
--- /dev/null
+//<Script type="text/javascript">
+
+print("Use seed gtkrun.js Builder");
--- /dev/null
+//<Script type="text/javascript">
+/**
+ *
+ * simple console wrapper - emulates what you would expect from console
+ *
+ * in theory could be replaced with a 'in-line console'
+ *
+ * provides 'dump' in addtion to 'log'
+ *
+ */
+
+
+function log (v)
+{
+ print(v);
+}
+function dump (ar)
+{
+ print(_dump(ar, 0));
+}
+
+function _dump(arr,level)
+{
+ level = level || 0;
+
+ var dumped_text = "";
+
+
+
+ //The padding given at the beginning of the line.
+ var level_padding = "";
+
+ for(var j=0;j<level+1;j++) {
+ level_padding += " ";
+ }
+
+ if(level > 15) {
+ return level_padding + "[ ... to deep ...]\n";
+ }
+
+ if (typeof(arr) != 'object') { //Array/Hashes/Objects
+ return "===>"+arr+"<===("+typeof(arr)+")";
+ }
+
+ for(var item in arr) {
+ var value = arr[item];
+ if (item == 'prototype') {
+ continue;
+ }
+ switch (typeof(value)) {
+ case 'object' :
+ dumped_text += level_padding + "'" + item + "' ...\n";
+ dumped_text += _dump(value,level+1) + "\n";
+ break;
+
+ case 'function' :
+ dumped_text += level_padding + "'" + item + "' => FUNCTION \n";
+ break;
+
+ default:
+ dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
+ break;
+ }
+ }
+
+ return dumped_text;
+}
--- /dev/null
+//<script type="text/javascript">
+
+/**
+ * This is a hacky generator to generate element definitions for the Roo version from the database
+ *
+ * Let's see if libgda can be used to generate our Readers for roo...
+ *
+ * Concept - conect to database..
+ *
+ * list tables
+ *
+ * extra schemas..
+ *
+ * write readers..
+ *
+ * usage: seed generate.js
+ *
+ *
+ *
+ *
+ *Hack needed to latest GLib-2.0.gir
+ *
+ * <record name="KeyFile" c:type="GKeyFile" disguised="1">
+ <constructor name="new" c:identifier="g_key_file_new">
+ <return-value transfer-ownership="full">
+ <type name="KeyFile" c:type="GKeyFile*"/>
+ </return-value>
+ </constructor>
+ *
+ *
+ * remove introspectable =0 from g_key_file_get_groups
+ * and add transfer-owneership = none to return value
+ * remove introspectable =0 from g_key_file_get_keys
+ * and add transfer-owneership = none to return value*
+ *
+ */
+Gda = imports.gi.Gda;
+GObject = imports.gi.GObject;
+
+GLib = imports.gi.GLib;
+
+console = imports.console;
+File = imports.File.File;
+Options = imports.Options.Options;
+
+//Gda.init();
+
+var prov = Gda.Config.list_providers ();
+//print(prov.dump_as_string());
+
+var o = new Options({
+ help_description : 'Element builder for App Builder based on database schema',
+
+ options: [
+ { arg_long : 'DBTYPE' , arg_short : 't', description : 'Database Type (eg. MySQL or PostgreSQL ' },
+ { arg_long : 'DBNAME' , arg_short : 'd', description : 'Database Name' },
+ { arg_long : 'USERNAME' , arg_short : 'u', description : 'Username'},
+ { arg_long : 'PASSWORD' , arg_short : 'p', description : 'Password' , arg_default :'' },
+ { arg_long : 'INI' , arg_short : 'I', description :
+ 'Either base directory which has Pman/***/DataObjects/***.links.ini or location of ini file.' },
+ ]
+
+})
+
+
+
+var cfg = o.parse(Seed.argv);
+print(JSON.stringify(cfg, null,4));
+
+var cnc = Gda.Connection.open_from_string (cfg.DBTYPE,
+ "DB_NAME=" + cfg.DBNAME,
+ "USERNAME=" + cfg.USERNAME + ';PASSWORD=' + cfg.PASSWORD,
+ Gda.ConnectionOptions.NONE, null);
+
+
+
+
+
+
+Gda.DataSelect.prototype.fetchAll = function()
+{
+ var cols = [];
+
+ for (var i =0;i < this.get_n_columns(); i++) {
+ cols.push(this.get_column_name(i));
+ }
+ //print(JSON.stringify(cols, null,4));
+ var iter = this.create_iter();
+ var res = [];
+ //print(this.get_n_rows());
+ var _this = this;
+ for (var r = 0; r < this.get_n_rows(); r++) {
+
+ // single clo..
+ //print("GOT ROW");
+ if (cols.length == 1) {
+ res.push(this.get_value_at(0,r).get_string());
+ continue;
+ }
+ var add = { };
+
+ cols.forEach(function(n,i) {
+ var val = _this.get_value_at(i,r);
+ var type = GObject.type_name(val.g_type) ;
+ var vs = ['GdaBinary', 'GdaBlob' ].indexOf(type) > -1 ? val.value.to_string(1024) : val.value;
+ //print(n + " : TYPE: " + GObject.type_name(val.g_type) + " : " + vs);
+ //print (n + '=' + iter.get_value_at(i).value);
+ add[n] = vs;
+ });
+
+ res.push(add);
+
+ }
+ return res;
+
+}
+
+var map = {
+ 'date' : 'date',
+ 'datetime' : 'date',
+ 'timestamp with time zone' : 'date',
+ 'timestamp without time zone' : 'date',
+ 'time' : 'string', //bogus
+ 'int' : 'int',
+ 'integer' : 'int',
+ 'bigint' : 'int',
+ 'double' : 'float',
+ 'tinyint' : 'int',
+ 'smallint' : 'int',
+ 'decimal' : 'float',
+ 'float' : 'float',
+ 'numeric' : 'float',
+ 'char' : 'string',
+ 'character' : 'string',
+ 'character varying' : 'string',
+ 'varchar' : 'string',
+ 'text' : 'string',
+ 'longtext' : 'string',
+ 'tinytext' : 'string',
+ 'mediumtext' : 'string',
+ 'enum' : 'string',
+ 'timestamp' : 'number',
+ 'blob' : 'text',
+ 'bytea' : 'text',
+ 'boolean' : 'int',
+ 'text[]' : 'string',
+
+}
+
+var ini = { }
+
+function readIni(fn)
+{
+ print('Read INI : ' + fn);
+ var key_file = new GLib.KeyFile.c_new();
+ if (!key_file.load_from_file (fn , GLib.KeyFileFlags.NONE )) {
+ return;
+ }
+
+ var groups = key_file.get_groups();
+ groups.forEach(function(g) {
+ //print("KEY:"+g);
+ ini[g] = {}
+
+ var keys = key_file.get_keys(g);
+ if (!keys) { return; }
+
+ keys.forEach(function(k) {
+ print("GET val: " + k);
+ ini[g][k] = key_file.get_value(g,k);
+ print(ini[g][k] );
+ });
+ //print("DONE KEY:"+g);
+ });
+ //print("DONE KEYS");
+}
+
+if (File.isFile(cfg.INI)) {
+ if (cfg.INI.match(/links\.ini$/)) {
+ readIni(cfg.INI);
+ } else {
+ readIni(cfg.INI.replace(/\.ini$/, ".links.ini"));
+ }
+}
+
+
+if (File.isDirectory(cfg.INI)) {
+
+
+ //--- load ini files..
+ // this is very specific.
+
+ var dirs = File.list( cfg.INI + '/Pman').filter(
+ function(e) {
+ if (!File.isDirectory(cfg.INI + '/Pman/' + e + '/DataObjects')) {
+ return false;
+ }
+ return true;
+ }
+ );
+
+
+ dirs.forEach(function(d) {
+ // this currently misses the web.*/Pman/XXXX/DataObjects..
+ var path = cfg.INI + '/Pman/' + d + '/DataObjects';
+
+ if (!File.isDirectory(path)) {
+ return; //skip
+ }
+ var inis = File.list(path).filter(
+ function(e) { return e.match(/\.links\.ini$/); }
+ );
+ if (!inis.length) {
+ return;
+ }
+
+ inis.forEach(function(i) {
+ readIni(path + '/' + i);
+
+ })
+
+ });
+ // look at web.XXXX/Pman/XXX/DataObjects/*.ini
+ var inis = File.list(cfg.INI).filter(
+ function(e) { return e.match(/\.links\.ini$/); }
+ )
+
+ inis.forEach(function(i) {
+ readIni(path + '/' + i);
+
+ })
+
+
+}
+//print(JSON.stringify(ini, null,4));
+ //console.dump(ini);
+print("DONE INI");
+
+ //Seed.quit();
+
+//GLib.key_file_load_from_file (key_file, String file, KeyFileFlags flags) : Boolean
+
+
+switch(cfg.DBTYPE) {
+ case "MySQL":
+ query_tables = "SHOW TABLES";
+ query_describe_table = "DESCRIBE `%s`";
+ break;
+
+ case 'PostgreSQL':
+ query_tables = "select c.relname FROM pg_catalog.pg_class c " +
+ "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace " +
+ "WHERE c.relkind IN ('r','') AND n.nspname NOT IN ('pg_catalog', 'pg_toast')" +
+ "AND pg_catalog.pg_table_is_visible(c.oid) ";
+ query_describe_table =
+ "SELECT " +
+ "f.attnum AS number, " +
+ "f.attname AS Field, " +
+ "f.attnum, " +
+ "CASE WHEN f.attnotnull = 't' THEN 'NO' ELSE 'YES' END AS isNull, " +
+ "pg_catalog.format_type(f.atttypid,f.atttypmod) AS Type, " +
+ "CASE WHEN p.contype = 'p' THEN 't' ELSE 'f' END AS primarykey, " +
+ "CASE WHEN p.contype = 'u' THEN 't' ELSE 'f' END AS uniquekey, " +
+ "CASE WHEN p.contype = 'f' THEN g.relname END AS foreignkey, " +
+ "CASE WHEN p.contype = 'f' THEN p.confkey END AS foreignkey_fieldnum, " +
+ "CASE WHEN p.contype = 'f' THEN g.relname END AS foreignkey, " +
+ "CASE WHEN p.contype = 'f' THEN p.conkey END AS foreignkey_connnum, " +
+ "CASE WHEN f.atthasdef = 't' THEN d.adsrc END AS default " +
+ "FROM pg_attribute f JOIN pg_class c ON c.oid = f.attrelid " +
+ " JOIN pg_type t ON t.oid = f.atttypid " +
+ " LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum " +
+ " LEFT JOIN pg_namespace n ON n.oid = c.relnamespace " +
+ " LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY ( p.conkey ) " +
+ " LEFT JOIN pg_class AS g ON p.confrelid = g.oid " +
+ "WHERE c.relkind = 'r'::char AND n.nspname = '%n' " +
+ "AND c.relname = '%s' AND f.attnum > 0 ORDER BY number";
+
+
+
+ break;
+ default:
+ throw {
+ name: "ArgumentError",
+ message: "Invalid data base type " + cfg.DBTYPE + " should be MySQL or PostgreSQL"
+ };
+
+/*
+ "Field": "province",
+ "Type": "varchar(255)",
+ "Null": "NO", << or is null
+ "Key": null,
+ "Default": null,
+ "Extra":
+*/
+}
+
+
+
+
+var tables = cnc.execute_select_command( query_tables).fetchAll();
+print(JSON.stringify(tables));
+
+var readers = [];
+tables.forEach(function(table) {
+ //print(table);
+ var schema = cnc.execute_select_command(
+ query_describe_table.replace(/%s/, table).replace(/%n/,'public')
+ ).fetchAll();
+
+
+ var reader = [];
+ var colmodel = [];
+ var combofields= [ { name : 'id', type: 'int' } ]; // technically the primary key..
+
+ var form = {}
+
+ var firstTxtCol = '';
+
+ //print(JSON.stringify(schema, null,4)); Seed.quit();
+
+ schema.forEach(function(e) {
+ e.Type = e.Type || e.type;
+ e.Field = e.Field || e.field;
+
+ var type = e.Type.match(/([^(]+)\(([^\)]+)\)/);
+ var row = { };
+ if (type) {
+ e.Type = type[1];
+ e.Size = type[2];
+ }
+
+
+
+ row.name = e.Field;
+
+
+ if (typeof(map[e.Type]) == 'undefined') {
+ console.dump(e);
+ throw {
+ name: "ArgumentError",
+ message: "Unknown mapping for type : " + e.Type
+ };
+ }
+ row.type = map[e.Type];
+
+ if (row.type == 'string' && !firstTxtCol.length) {
+ firstTxtCol = row.name;
+ }
+
+ if (row.type == 'date') {
+ row.dateFormat = 'Y-m-d';
+ }
+ reader.push(row);
+
+ if (combofields.length == 1 && row.type == 'string') {
+ combofields.push(row);
+ }
+
+
+ var title = row.name.replace(/_id/, '').replace(/_/g, ' ');
+ title = title[0].toUpperCase() + title.substring(1);
+
+ colmodel.push({
+ "xtype": "ColumnModel",
+ "header": title,
+ "width": row.type == 'string' ? 200 : 75,
+ "dataIndex": row.name,
+ "|renderer": row.type != 'date' ?
+ "function(v) { return String.format('{0}', v); }" :
+ "function(v) { return String.format('{0}', v ? v.format('d/M/Y') : ''); }" , // special for date
+ "|xns": "Roo.grid",
+ "*prop": "colModel[]"
+ });
+ var xtype = 'TextField';
+
+
+ if (row.type == 'number') {
+ xtype = 'NumberField';
+ }
+ if (row.type == 'date') {
+ xtype = 'DateField';
+ }
+ if (e.Type == 'text') {
+ xtype = 'TextArea';
+ }
+ if (row.name == 'id') {
+ xtype = 'Hidden';
+ }
+ // what about booleans.. -> checkboxes..
+
+
+
+ form[row.name] = {
+ fieldLabel : title,
+ name : row.name,
+ width : row.type == 'string' ? 200 : 75,
+ '|xns' : 'Roo.form',
+ xtype : xtype
+ }
+ if (xtype == 'DateField') {
+ form[row.name].format = 'Y-m-d';
+ form[row.name].width = 100;
+ }
+
+ if (xtype == 'TextArea') {
+ form[row.name].height = 100;
+ }
+ if (xtype == 'Hidden') {
+ delete form[row.name].fieldLabel;
+ delete form[row.name].width;
+ }
+
+ });
+
+ var combo = {
+ '|xns' : 'Roo.form',
+ xtype: 'ComboBox',
+ allowBlank : false,
+ editable : false,
+ emptyText : 'Select ' + table,
+ forceSelection : true,
+ listWidth : 400,
+ loadingText: 'Searching...',
+ minChars : 2,
+ pageSize : 20,
+ qtip: 'Select ' + table,
+ selectOnFocus: true,
+ triggerAction : 'all',
+ typeAhead: true,
+
+ width: 300,
+
+
+
+ tpl : '<div class="x-grid-cell-text x-btn button"><b>{name}</b> </div>', // SET WHEN USED
+ queryParam : '',// SET WHEN USED
+ fieldLabel : table, // SET WHEN USED
+ valueField : 'id',
+ displayField : '', // SET WHEN USED eg. project_id_name
+ hiddenName : '', // SET WHEN USED eg. project_id
+ name : '', // SET WHEN USED eg. project_id_name
+ items : [
+ {
+
+ '*prop' : 'store',
+ 'xtype' : 'Store',
+ '|xns' : 'Roo.data',
+ 'remoteSort' : true,
+ '|sortInfo' : '{ direction : \'ASC\', field: \'id\' }',
+ listeners : {
+ '|beforeload' : 'function (_self, o)' +
+ "{\n" +
+ " o.params = o.params || {};\n" +
+ " // set more here\n" +
+ "}\n"
+ },
+ items : [
+ {
+ '*prop' : 'proxy',
+ 'xtype' : 'HttpProxy',
+ 'method' : 'GET',
+ '|xns' : 'Roo.data',
+ '|url' : "baseURL + '/Roo/" + table + ".php'",
+ },
+
+ {
+ '*prop' : 'reader',
+ 'xtype' : 'JsonReader',
+ '|xns' : 'Roo.data',
+ 'id' : 'id',
+ 'root' : 'data',
+ 'totalProperty' : 'total',
+ '|fields' : JSON.stringify(combofields)
+
+ }
+ ]
+ }
+ ]
+ }
+
+
+
+
+ //print(JSON.stringify(reader,null,4));
+ readers.push({
+ table : table ,
+ combo : combo,
+ combofields : combofields,
+ reader : reader,
+ oreader : JSON.parse(JSON.stringify(reader)), // dupe it..
+ colmodel : colmodel,
+ firstTxtCol : firstTxtCol,
+ form : form
+ });
+
+ //console.dump(schema );
+
+
+});
+
+
+
+// merge in the linked tables..
+readers.forEach(function(reader) {
+ if (typeof(ini[reader.table]) == 'undefined') {
+
+ return;
+ }
+ print("OVERLAY - " + reader.table);
+ // we have a map..
+ for (var col in ini[reader.table]) {
+ var kv = ini[reader.table][col].split(':');
+
+
+ var add = readers.filter(function(r) { return r.table == kv[0] })[0];
+ if (!add) {
+ continue;
+ }
+ // merge in data (eg. project_id => project_id_*****
+
+ add.oreader.forEach(function(or) {
+ reader.reader.push({
+ name : col + '_' + or.name,
+ type : or.type
+ });
+ });
+
+ // col is mapped to something..
+ var combofields = add.combofields;
+ if (add.combofields.length < 2) {
+ continue;
+ }
+ if (typeof(reader.form[col]) == 'undefined') {
+ print (JSON.stringify(reader.form, null,4));
+ print("missing linked column " + col);
+ continue;
+ }
+
+ var combofields_name = add.combofields[1].name;
+ var old = reader.form[col];
+ reader.form[col] = JSON.parse(JSON.stringify(add.combo)); // clone
+ reader.form[col].queryParam = 'query[' + combofields_name + ']';// SET WHEN USED
+ reader.form[col].fieldLabel = old.fieldLabel; // SET WHEN USED
+ reader.form[col].hiddenName = old.name; // SET WHEN USED eg. project_id
+ reader.form[col].displayField = combofields_name; // SET WHEN USED eg. project_id
+ reader.form[col].name = old.name + '_' + combofields_name; // SET WHEN USED eg. project_id_name
+ reader.form[col].tpl = '<div class="x-grid-cell-text x-btn button"><b>{' + combofields_name +'}</b> </div>'; // SET WHEN USED
+
+
+ };
+
+
+});
+
+//readers.forEach(function(reader) {
+// delete reader.oreader;
+//});
+
+
+
+
+
+//print(JSON.stringify(readers, null, 4));
+
+readers.forEach(function(reader) {
+
+
+ var dir = GLib.get_home_dir() + '/.Builder/Roo.data.JsonReader';
+ if (!File.isDirectory(dir)) {
+ print("mkdir " + dir);
+ File.mkdir(dir);
+ }
+
+ // READERS
+ print("WRITE: " + dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+
+
+ var jreader = {
+ '|xns' : 'Roo.data',
+ xtype : "JsonReader",
+ totalProperty : "total",
+ root : "data",
+ '*prop' : "reader",
+ id : 'id', // maybe no..
+
+ '|fields' : JSON.stringify(reader.reader, null,4).replace(/"/g,"'")
+ };
+
+ File.write(
+ dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+ JSON.stringify(jreader, null, 4)
+ )
+
+
+ // GRIDS
+ dir = GLib.get_home_dir() + '/.Builder/Roo.GridPanel';
+ if (!File.isDirectory(dir)) {
+ print("mkdir " + dir);
+ File.mkdir(dir);
+ }
+
+
+ print("WRITE: " + dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+
+ File.write(
+ dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+
+
+ JSON.stringify({
+ '|xns' : 'Roo',
+ xtype : "GridPanel",
+ "title": reader.table,
+ "fitToframe": true,
+ "fitContainer": true,
+ "tableName": reader.table,
+ "background": true,
+ "region" : 'center',
+ "listeners": {
+ "|activate": "function() {\n _this.panel = this;\n if (_this.grid) {\n _this.grid.footer.onClick('first');\n }\n}"
+ },
+ "items": [
+ {
+ "*prop": "grid",
+ "xtype": "Grid",
+ "autoExpandColumn": reader.firstTxtCol,
+ "loadMask": true,
+ "listeners": {
+ "|render": "function() \n" +
+ "{\n" +
+ " _this.grid = this; \n" +
+ " //_this.dialog = Pman.Dialog.FILL_IN\n" +
+ " if (_this.panel.active) {\n" +
+ " this.footer.onClick('first');\n" +
+ " }\n" +
+ "}",
+ "|rowdblclick": "function (_self, rowIndex, e)\n" +
+ "{\n" +
+ " if (!_this.dialog) return;\n" +
+ " _this.dialog.show( this.getDataSource().getAt(rowIndex).data, function() {\n" +
+ " _this.grid.footer.onClick('first');\n" +
+ " }); \n" +
+ "}\n"
+ },
+ "|xns": "Roo.grid",
+
+ "items": [
+ {
+ "*prop": "dataSource",
+ "xtype": "Store",
+ remoteSort : true,
+ '|sortInfo' : "{ field : '" + reader.firstTxtCol + "', direction: 'ASC' }",
+ "|xns": "Roo.data",
+ "items": [
+
+ {
+ "*prop": "proxy",
+ "xtype": "HttpProxy",
+ "method": "GET",
+ "|url": "baseURL + '/Roo/" + reader.table + ".php'",
+ "|xns": "Roo.data"
+ },
+ jreader
+ ]
+ },
+ {
+ "*prop": "footer",
+ "xtype": "PagingToolbar",
+ "pageSize": 25,
+ "displayInfo": true,
+ "displayMsg": "Displaying " + reader.table + "{0} - {1} of {2}",
+ "emptyMsg": "No " + reader.table + " found",
+ "|xns": "Roo"
+ },
+ {
+ "*prop": "toolbar",
+ "xtype": "Toolbar",
+ "|xns": "Roo",
+ "items": [
+ {
+ "text": "Add",
+ "xtype": "Button",
+ "cls": "x-btn-text-icon",
+ "|icon": "Roo.rootURL + 'images/default/dd/drop-add.gif'",
+ "listeners": {
+ "|click": "function()\n"+
+ "{\n"+
+ " if (!_this.dialog) return;\n" +
+ " _this.dialog.show( { id : 0 } , function() {\n"+
+ " _this.grid.footer.onClick('first');\n"+
+ " }); \n"+
+ "}\n"
+ },
+ "|xns": "Roo.Toolbar"
+ },
+ {
+ "text": "Edit",
+ "xtype": "Button",
+ "cls": "x-btn-text-icon",
+ "|icon": "Roo.rootURL + 'images/default/tree/leaf.gif'",
+ "listeners": {
+ "|click": "function()\n"+
+ "{\n"+
+ " var s = _this.grid.getSelectionModel().getSelections();\n"+
+ " if (!s.length || (s.length > 1)) {\n"+
+ " Roo.MessageBox.alert(\"Error\", s.length ? \"Select only one Row\" : \"Select a Row\");\n"+
+ " return;\n"+
+ " }\n"+
+ " if (!_this.dialog) return;\n" +
+ " _this.dialog.show(s[0].data, function() {\n"+
+ " _this.grid.footer.onClick('first');\n"+
+ " }); \n"+
+ " \n"+
+ "}\n"
+
+ },
+ "|xns": "Roo.Toolbar"
+ },
+ {
+ "text": "Delete",
+ "cls": "x-btn-text-icon",
+ "|icon": "rootURL + '/Pman/templates/images/trash.gif'",
+ "xtype": "Button",
+ "listeners": {
+ "|click": "function()\n"+
+ "{\n"+
+ " Pman.genericDelete(_this, '" + reader.table + "'); \n"+
+ "}\n"+
+ " "
+ },
+ "|xns": "Roo.Toolbar"
+ }
+ ]
+ }, // end toolbar
+ ].concat( reader.colmodel)
+ }
+ ]
+
+
+ }, null, 4)
+ )
+
+ /// FORMS..
+
+ dir = GLib.get_home_dir() + '/.Builder/Roo.form.Form';
+ if (!File.isDirectory(dir)) {
+ print("mkdir " + dir);
+ File.mkdir(dir);
+ }
+ var formElements = [];
+ var formHeight = 50;
+ for (var k in reader.form) {
+ if (k == 'id') { // should really do primary key testing..
+ continue;
+ }
+ formHeight += reader.form[k].xtype == 'TextArea' ? 100 : 30;
+
+ formElements.push(reader.form[k]);
+ }
+ if (reader.form['id']) {
+ formElements.push(reader.form['id']);
+ }
+
+
+ print("WRITE: " + dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+ var frmCfg =
+ {
+ '|xns' : 'Roo.form',
+ xtype : "Form",
+ listeners : {
+ "|actioncomplete" : "function(_self,action)\n"+
+ "{\n"+
+ " if (action.type == 'setdata') {\n"+
+ " //_this.dialog.el.mask(\"Loading\");\n"+
+ " //this.load({ method: 'GET', params: { '_id' : _this.data.id }});\n"+
+ " return;\n"+
+ " }\n"+
+ " if (action.type == 'load') {\n"+
+ " _this.dialog.el.unmask();\n"+
+ " return;\n"+
+ " }\n"+
+ " if (action.type =='submit') {\n"+
+ " \n"+
+ " _this.dialog.el.unmask();\n"+
+ " _this.dialog.hide();\n"+
+ " \n"+
+ " if (_this.callback) {\n"+
+ " _this.callback.call(_this, _this.form.getValues());\n"+
+ " }\n"+
+ " _this.form.reset();\n"+
+ " return;\n"+
+ " }\n"+
+ "}\n",
+
+ "|rendered" : "function (form)\n"+
+ "{\n"+
+ " _this.form= form;\n"+
+ "}\n"
+ },
+ method : "POST",
+ style : "margin:10px;",
+ "|url" : "baseURL + '/Roo/" + reader.table + ".php'",
+ items : formElements
+ };
+
+
+ File.write(
+ dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+
+
+ JSON.stringify( frmCfg, null, 4)
+ );
+
+
+
+
+
+ /// COMBO..
+
+ dir = GLib.get_home_dir() + '/.Builder/Roo.form.ComboBox';
+ if (!File.isDirectory(dir)) {
+ print("mkdir " + dir);
+ File.mkdir(dir);
+ }
+
+ print("WRITE: " + dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+
+ File.write(
+ dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+
+
+ JSON.stringify(reader.combo, null, 4)
+ );
+
+
+
+
+
+
+ // DIALOG.
+
+
+ dir = GLib.get_home_dir() + '/.Builder/Roo.LayoutDialog';
+ if (!File.isDirectory(dir)) {
+ print("mkdir " + dir);
+ File.mkdir(dir);
+ }
+ var formElements = [];
+ for (var k in reader.form) {
+ if (k == 'id') { // should really do primary key testing..
+ continue;
+ }
+ formElements.push(reader.form[k]);
+ }
+ formElements.push(reader.form['id']);
+
+ print("WRITE: " + dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+
+ File.write(
+ dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+
+
+ JSON.stringify({
+
+ "closable": false,
+ "collapsible": false,
+ "height": formHeight,
+ "resizable": false,
+ "title": "Edit / Create " + reader.table,
+ "width": 400,
+ "modal" : true,
+ "xtype": "LayoutDialog",
+ "|xns": "Roo",
+ "items": [
+ {
+ "|xns": "Roo",
+ "xtype": "LayoutRegion",
+ "*prop": "center"
+ },
+ {
+ "region": "center",
+ "xtype": "ContentPanel",
+ "|xns": "Roo",
+ "items": [
+ frmCfg
+ ]
+ },
+
+ {
+ "listeners": {
+ "click": "function (_self, e)\n{\n _this.dialog.hide();\n}"
+ },
+ "*prop": "buttons[]",
+ "text": "Cancel",
+ "xtype": "Button",
+ "|xns": "Roo"
+ },
+ {
+ "listeners": {
+ "click": "function (_self, e)\n{\n // do some checks?\n \n \n _this.dialog.el.mask(\"Saving\");\n _this.form.doAction(\"submit\");\n\n}"
+ },
+ "*prop": "buttons[]",
+ "text": "Save",
+ "xtype": "Button",
+ "|xns": "Roo"
+ }
+ ]
+ }, null,4)
+ );
+
+
+
+});
+
+
--- /dev/null
+#!/usr/bin/seed
+//<Script type="text/javascript">
+/**
+ * runtime file
+ * takes a gtk project directory, and turns it into an application!
+ * by compling the files into JS files..
+ *
+ * Initially developed for runtime testing. (the vte runner)
+ *
+ * Might be the way to go for full runtime
+ *
+ *
+ * Usage: (call with wrapper to set up directories..)
+ * sh builder.sh
+ *
+ * Concepts..
+ * a) load dependancies.. (eg. gi's..) - derived later?
+ * Gtk.init()
+ *
+ * loop the files (find .bjs)
+ * - comple to js (if not exist // or force enabled..)
+ * b) load all the files
+ *
+ * Gtk.main();
+ *
+ */
+// autogen?
+
+// sort out import path - this is a bit of a mess..
+GIRepository = imports.gi.GIRepository;
+GLib = imports.gi.GLib;
+
+// we add this in, as it appears to get lost sometimes if we set it using the ENV. variable in builder.sh
+GIRepository.Repository.prepend_search_path(GLib.get_home_dir() + '/.Builder/girepository-1.2');
+//print(JSON.stringify(GIRepository.IRepository.get_search_path()));
+
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+Pango = imports.gi.Pango;
+
+Gio = imports.gi.Gio;
+GObject = imports.gi.GObject;
+GtkSource = imports.gi.GtkSource;
+WebKit = imports.gi.WebKit;
+Vte = imports.gi.Vte;
+
+//Gdl = imports.gi.Gdl;
+
+//GtkClutter = imports.gi.GtkClutter;
+
+
+if (typeof(GtkClutter) != 'undefined') {
+ GtkClutter.init(Seed.argv);
+}
+
+
+File = imports.File.File;
+
+XObject = imports.XObject.XObject;
+//XObject.debug = true;
+Gtk.init(Seed.argv);
+
+Globals = imports.Globals;
+
+
+imports.searchPath.push('/'); // allow global paths..
+// error checking todo..
+var files = File.list(Seed.argv[2]);
+var olist = [];
+
+var gtkbuilder = false;
+files.forEach(function(f) {
+ var fp = Seed.argv[2] + '/' + f;
+
+
+
+ if (!fp.match(/\.js$/)) {
+ return;
+ }
+ var js = fp; //.replace(/\.js$/, '.js');
+ if (File.isFile(js)) {
+ // check file time.. = bjs is less than compiled file..
+ //if (File.mtime(fp) < File.mtime(js)) {
+ XObject.log("LOADING" + js);
+ olist.push(imports[js]);
+ return;
+ //}
+ // Compiling BJS is depreciated..
+ //olist.push(imports[js]);
+ //return;
+
+ }
+
+ return;
+ /*
+ var gtkbuilder = new imports.Builder.Provider.File.Gtk.Gtk({ path : fp });
+ gtkbuilder.loadItems(function() { });
+ XObject.log("COMPILING" + js);
+ var fn = gtkbuilder.saveJS();
+ if (fn === false) { // skip files that do not contain anythng!
+ return;
+ }
+ olist.push(imports[fn]);
+ */
+
+});
+
+
+
+
+Gtk.main();
+
--- /dev/null
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+Pango = imports.gi.Pango;
+XObject = imports.XObject.XObject;
+Gtk.init(null,null);
+
+
+_top=new XObject({xtype: Gtk.Window, "type":Gtk.WindowType.TOPLEVEL, "title":"Application Builder", "border_width":2, "id":"builder-0", "xtreepath":"0"})
+
+;_top.init();
+_top.el.show_all();
+Gtk.main();