Procházet zdrojové kódy

Bug fixes on examples

mingodad před 10 roky
rodič
revize
14a58ea041

+ 6 - 5
SquiLu-ourbiz/companies-uk.nut

@@ -17,6 +17,7 @@ local function getCompaniesUkDBFileName(){
 	//return APP_CODE_FOLDER + "/../../companies-uk/companies-uk-RG-2014-07.db";
 	//return APP_CODE_FOLDER + "/../../companies-uk/companies-uk-2013-10.db";
 	return APP_CODE_FOLDER + "/../../companies-uk/companies-uk-2014-07.db";
+	//return "file:companies_uk_db?mode=memory&cache=shared";
 }
 
 local companiesUkDB = null;
@@ -631,7 +632,7 @@ local my_uri_handlers = {
 			data.rows <- result[0];
 			data.limit <- result[2];
 			if (!data.sicSearchResults && data.rows.len() == 1) {
-					request.print(format("HTTP/1.1 302 Found\r\nLocation: /view?id=%d\r\n\r\n", data.rows[0][0]));
+					request.print(format("HTTP/1.1 302 Found\r\nLocation: /view?id=%d\r\nConnection: Keep-Alive\r\n\r\n", data.rows[0][0]));
 					return true;
 			}
 			if (strHasContent(data.search_origin_post_code)) {
@@ -643,7 +644,7 @@ local my_uri_handlers = {
 		mFile.clear();
 		data.mix_write <- function(str) {if(str) mFile.write(str);}
 		fillTemplate("index.tpl", data, AT_DEV_DBG);
-		request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %d\r\n\r\n", mFile.len()));
+		request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: Keep-Alive\r\nContent-Length: %d\r\n\r\n", mFile.len()));
 		request.write_blob(gmFile);
 		return true;
 	},
@@ -677,7 +678,7 @@ local my_uri_handlers = {
 		mFile.clear();
 		data.mix_write <- function(str) {mFile.write(str || "");}
 		fillTemplate("index.tpl", data, AT_DEV_DBG);
-		request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %d\r\n\r\n", mFile.len()));
+		request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: Keep-Alive\r\nContent-Length: %d\r\n\r\n", mFile.len()));
 		request.write_blob(mFile);
 		return true;
 	},
@@ -703,13 +704,13 @@ local my_uri_handlers = {
 		
 
 		result = var2json(result[0]);
-		request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: %d\r\n\r\n", result.len()));
+		request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: Keep-Alive\r\nContent-Length: %d\r\n\r\n", result.len()));
 		request.print(result);
 		return true;
 	},
 	["/hello"] = function(request){
 		local response = "<html><body>Hello World !</body></html>"
-		request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %d\r\n\r\n%s", response.len(), response));
+		request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: Keep-Alive\r\nContent-Length: %d\r\n\r\n%s", response.len(), response));
 		return true;
 	},
 }

+ 1 - 1
SquiLu-ourbiz/fluid2SquiLu.nut

@@ -569,7 +569,7 @@ function GetAccessMode(t, mode){
 FindMembers.Function <- function(t, list){
 	if (t.name == "") t.name = "make_window()";
 	local name = t.name.match("[%w_]+");
-	if (t.parent.name == name) { // constructor
+	if (t.parent.rawget("name",  "") == name) { // constructor
 		t.name = "__constructor()";
 		t.parent.constructor <- t.name;
 	}

+ 1 - 1
SquiLu-ourbiz/mk-exe

@@ -1,2 +1,2 @@
-squilu -c squiluc.nut ourbiz-fltk.nut -L chartstatistics.lua dadbiz-gui.lua entities-db.lua entities.lua groupsedit.lua historystatistics.lua images-db.lua images.lua invoice-types.lua invoices-db.lua invoices.lua delivery_calc.lua printinghtml.lua products-db.lua products.lua  ../lib/dadlib.lua ../lib/app-utils.lua ../lib/db-utils.lua ../lib/mycalendar-gui.lua ../lib/mycalendar.lua ../lib/mywidgets.lua  ../lib/mybarchart.lua ../lib/json.lua printing.lua
+squilu -c squiluc.nut ourbiz-fltk.nut
 squilu squilufreeze.nut /home/mingo/bin/squilu luac.out ourbiz

+ 2 - 2
SquiLu-ourbiz/ourbiz-fltk.nut

@@ -353,7 +353,7 @@ class Base_Window extends Fl_Window {
 	_sab = null;
 
 	constructor(px, py, pw, ph, pl=null) {
-		if(px < 0) base.constructor(pw, ph, pl);
+		if(px < 0 || py < 0) base.constructor(pw, ph, pl);
 		else base.constructor(px, py, pw, ph, pl);
 		_child_windows = {};
 		_db_map = {};
@@ -417,7 +417,7 @@ class Base_Window extends Fl_Window {
 		if(!win){
 			win = new WindowClass();
 			//win.label(winName);
-			_child_windows[winName] <- win.weakref();
+			_child_windows[winName] <- win; //.weakref();
 		}
 		return win;
 	}

+ 17 - 8
SquiLu-ourbiz/ourbiz.nut

@@ -196,6 +196,7 @@ local function getOurbizDBFileName(){
 	if(globals.rawget("jniLog", false)) return APP_CODE_FOLDER + "/ourbiz.db";
 	if(globals.rawget("WIN32", false)) return APP_CODE_FOLDER + "/../../ourbiz-uk/ourbiz.db";
 	return "/home/mingo/dev/FrontAccountLua/ourbiz.db";
+	//return "file:ourbiz_db?mode=memory&cache=shared";
 }
 
 local ourbizDB = null;
@@ -457,7 +458,7 @@ local DB_Manager = class {
 		}
 		local result = stmt.step();
 		stmt.finalize()
-		if (result == SQLite3Stmt.DONE) return db.last_insert_rowid();
+		if (result == SQLite3Stmt.DONE) return db.last_row_id();
 		throw db.errmsg();
 	}
 
@@ -3119,7 +3120,7 @@ local function ourbizDbMobile(request){
 	mFile.clear();
 	data.mix_write <- function(str){ if(str) mFile.write(str); };
 	fillTemplate("mobile-list.tpl", data, AT_DEV_DBG);
-	request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %d\r\n\r\n", mFile.len()));
+	request.print(format("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: Keep-Alive\r\nContent-Length: %d\r\n\r\n", mFile.len()));
 	request.write_blob(mFile);
 	return true;
 }
@@ -3149,6 +3150,7 @@ local function ourbizDbGetList(request){
 				request.print(format([==[
 HTTP/1.1 200 OK
 Content-type: application/pdf
+Connection: Keep-Alive
 Content-Disposition: attachment; filename=%s-list.pdf
 Content-Length: %d
 
@@ -3173,7 +3175,8 @@ Content-Length: %d
 		if (data){
 			//using string.format with binary data gives wrong results
 			gmFile.clear()
-			gmFile.write("HTTP/1.1 200 OK\r\nContent-type: text/plain; charset=x-user-defined\r\nContent-Length: ", data.len(), "\r\n\r\n", data);
+			gmFile.write("HTTP/1.1 200 OK\r\nContent-type: text/plain; charset=x-user-defined\r\nConnection: Keep-Alive\r\nContent-Length: ", 
+				data.len(), "\r\n\r\n", data);
 			request.write_blob(gmFile);
 			return true;
 		}
@@ -3202,6 +3205,7 @@ local function ourbizDbGetOne(request){
 			request.print(format([==[
 HTTP/1.1 200 OK
 Content-type: application/pdf
+Connection: Keep-Alive
 Content-Disposition: attachment; filename=%s-list.pdf
 Content-Length: %d
 
@@ -3227,7 +3231,8 @@ Content-Length: %d
 		if (data){
 			//using string.format with binary data gives wrong results
 			gmFile.clear();
-			gmFile.write("HTTP/1.1 200 OK\r\nContent-type: text/plain; charset=x-user-defined\r\nContent-Length: ", data.len(), "\r\n\r\n", data);
+			gmFile.write("HTTP/1.1 200 OK\r\nContent-type: text/plain; charset=x-user-defined\r\nConnection: Keep-Alive\r\nContent-Length: ", 
+				data.len(), "\r\n\r\n", data);
 			request.write_blob(gmFile);
 			return true;
 		}
@@ -3253,7 +3258,7 @@ local function ourbizDbGetBin(request){
 				local img_etag = stmt.col(0)
 				if( etag == img_etag) {
 					gmFile.clear();
-					gmFile.write("HTTP/1.1 304 OK\r\nContent-Length: 0\r\n\r\n");
+					gmFile.write("HTTP/1.1 304 OK\r\nContent-Length: 0\r\nConnection: Keep-Alive\r\n\r\n");
 					request.write_blob(gmFile);
 					stmt.finalize();
 					return result;
@@ -3280,7 +3285,10 @@ local function ourbizDbGetBin(request){
 				local img_etag = stmt.col(2)
 				//using string.format with binary data gives wrong results
 				gmFile.clear();
-				gmFile.write("HTTP/1.1 200 OK\r\nContent-type: ", mime, "\r\nContent-Length: ", data.len(), "\r\nETag: ", img_etag, "\r\n\r\n", data);
+				gmFile.write("HTTP/1.1 200 OK\r\nContent-type: ", mime, 
+					"\r\nContent-Length: ", data.len(), 
+					"\r\nConnection: Keep-Alive",
+					"\r\nETag: ", img_etag, "\r\n\r\n", data);
 				request.write_blob(gmFile);
 			}
 			stmt.finalize();
@@ -3327,7 +3335,8 @@ local function ourbizDbAction(request) {
 		if (data){
 			//using string.format with binary data gives wrong results
 			gmFile.clear();
-			gmFile.write("HTTP/1.1 200 OK\r\nContent-type: text/plain; charset=x-user-defined\r\nContent-Length: ", data.len(), "\r\n\r\n", data);
+			gmFile.write("HTTP/1.1 200 OK\r\nContent-type: text/plain; charset=x-user-defined\r\nConnection: Keep-Alive\r\nContent-Length: ", 
+				data.len(), "\r\n\r\n", data);
 			//debug_print(tostring(gmFile), "\n")
 			request.write_blob(gmFile);
 			return true;
@@ -3338,7 +3347,7 @@ local function ourbizDbAction(request) {
 
 add_uri_hanlders({
 	["/OURBIZ"] =function(request){
-		request.print("HTTP/1.1 200 OK\r\nServer: OurBiz\r\nContent-Length: 0\r\n\r\n");
+		request.print("HTTP/1.1 200 OK\r\nServer: OurBiz\r\nConnection: Keep-Alive\r\nContent-Length: 0\r\n\r\n");
 		return true;
 	},
 	["/GET-AUTH-REQ"] =function(request){

+ 9 - 7
SquiLu-ourbiz/pedidos2.nut

@@ -37,6 +37,8 @@ class Fl_Data_Table extends Flv_Data_Table {
 	}
 
 	function clear_data_rows(){
+		col(0);
+		cols(0);
 		row(0);
 		rows(0);
 		_data.clear();
@@ -328,13 +330,13 @@ class Pedidos2 extends PedidosWindow {
 			//print(key)
 			switch(key){
 				case FL_Menu: menu_bar_navigate(); break;
-				case FL_F+1: mostrar_ventana_ayuda(); break;
-				case FL_F+2: mostrar_ventana_pedido(); break;
-				case FL_F+3: mostrar_ventana_pedidos(); break;
-				case FL_F+4: mostrar_ventana_clientes(); break;
-				case FL_F+5: mostrar_ventana_articulos(); break;
-				case FL_F+6: mostrar_ventana_totales(); break;
-				case FL_F+9: mostrar_ventana_opciones(); break;
+				case FL_F1: mostrar_ventana_ayuda(); break;
+				case FL_F2: mostrar_ventana_pedido(); break;
+				case FL_F3: mostrar_ventana_pedidos(); break;
+				case FL_F4: mostrar_ventana_clientes(); break;
+				case FL_F5: mostrar_ventana_articulos(); break;
+				case FL_F6: mostrar_ventana_totales(); break;
+				case FL_F9: mostrar_ventana_opciones(); break;
 			}
 		}
 		

binární
SquiLu-ourbiz/s/images/huawei-u8150-ideos.jpg


+ 2 - 2
SquiLu-ourbiz/s/ourbiz/app-base.js

@@ -612,8 +612,8 @@ dad.Ajax = function(callback, params, cache)
       if (dad.inArray(verb, ['POST', 'PUT']))
          {
             this.request.setRequestHeader('Content-Type',   'application/x-www-form-urlencoded; charset=utf-8');
-            this.request.setRequestHeader('Content-length', what.length);
-            this.request.setRequestHeader('Connection',     'close');
+            //this.request.setRequestHeader('Content-Length', what.length);
+            //this.request.setRequestHeader('Connection',     'close');
          }
       if (headers)
          for (var i = 0, len = headers.length; i < len; i++)

+ 1 - 1
SquiLu-ourbiz/s/ourbiz/dadlib.js

@@ -13,7 +13,7 @@ Jaml.register('2TRDataTable', function(args) {
 		tr(
 		//(args.table_height || "100%") 65% for firefox
 			td({colspan:3, style: "width:100%;height:" + (args.table_height || "100%") + "; vertical-align:top;"},
-				div({'class': "divTable", style: "width:100%;height:100%;overflow:auto;"},
+				div({'class': "divTable", style: "width:100%;height:100%;overflow:auto;min-height:6em;"},
 					div({style:"height: 0px;"},
 						table({id: args.table_id, 'class': "wrappedTable"},
 							tbody(),

+ 1 - 1
SquiLu-ourbiz/s/ourbiz/gl-groups.js

@@ -66,7 +66,7 @@ function newGLGroupsListEditWindow(){
 			table_id: table_id,
 			table_header_id: table_header_id
 		}
-		data.table_height = "50%";
+		//data.table_height = "50%";
 		data.data_table = Jaml.render('2TRDataTable', data);
 
 		var win = dad.newWindow(newId,220,20, 460, 420, _tr(title), Jaml.render('GLGroupsListEdit', data));

+ 1 - 1
SquiLu-ourbiz/s/ourbiz/groups.js

@@ -2,7 +2,7 @@ Jaml.register('GroupsListEdit', function(args) {
 	var newIdBy2 = dad.newIdBy2calls;
 	form({action: "/DB/Action", method: "post", id: args.form_id, style: "width:100%;height:100%;"},
 		table({style: "width:100%;height:100%;"},
-			tr(td(div({id:args.div_tree_id, 'class': "divTree", style: "width:99%;overflow:auto;height:18em;"}))),
+			tr({style: "height:100%;"},td(div({id:args.div_tree_id, 'class': "divTree", style: "width:100%;height:100%;overflow:auto;min-height:8em;"}))),
 			tr(
 				td({'class': "editBox", style: "width:100%;"},
 					fieldset(legend(_tr("Edit Form")),

+ 12 - 12
SquiLu-ourbiz/s/ourbiz/jaml.js

@@ -67,14 +67,14 @@ Jaml.Node.prototype = {
   setAttributes: function(attrs) {
     for (var key in attrs) {
       //convert cls to class
-      var mappedKey = key == 'cls' ? 'class' : key;
+      var mappedKey = key === 'cls' ? 'class' : key;
 	  var mappedValue = attrs[key];
-	  if(typeof mappedValue == 'object'){
+	  if(typeof mappedValue === 'object'){
 		var ary = [];
 		for(var okey in mappedValue){
 			ary.push(okey);
 			ary.push(':');
-			ary.push(mappedValue[okey])
+			ary.push(mappedValue[okey]);
 			ary.push(';');
 		}
 		mappedValue = ary.join('');
@@ -117,13 +117,13 @@ Jaml.Node.prototype = {
     for (var key in this.attributes) {
       attrs.push(key + "=\"" + this.attributes[key] + "\"");
     }    
-    attrs.sort()
+    attrs.sort();
     //add any tag attributes
     for (var i=0; i<attrs.length; i++) {
       node.push(" " + attrs[i]);
     }
     
-    if (this.isSelfClosing() && this.children.length==0) {
+    if (this.isSelfClosing() && this.children.length===0) {
       node.push("/>\n");
     } else {
       node.push(">");
@@ -152,7 +152,7 @@ Jaml.Node.prototype = {
       var child = children[i];
       if (child instanceof Array) {
         var nestedChildren = child;
-        this.renderChildren(node, nestedChildren, lpad)
+        this.renderChildren(node, nestedChildren, lpad);
       } else {
         node.push(child.render(childLpad));
       }
@@ -167,7 +167,7 @@ Jaml.Node.prototype = {
     var childLength = this.children.length,
         multiLine   = childLength > 0;
     
-    if (childLength == 1 && this.children[0] instanceof Jaml.TextNode) multiLine = false;
+    if (childLength === 1 && this.children[0] instanceof Jaml.TextNode) multiLine = false;
     
     return multiLine;
   },
@@ -187,7 +187,7 @@ Jaml.Node.prototype = {
    */
   isSelfClosing: function() {
     for (var i = this.notSelfClosingTags.length - 1; i >= 0; i--) {
-      if (this.tagName == this.notSelfClosingTags[i]) return false;
+      if (this.tagName === this.notSelfClosingTags[i]) return false;
     }
 
     return true;
@@ -246,7 +246,7 @@ Jaml.Template.prototype = {
     
     //the 'data' argument can come in two flavours - array or non-array. Normalise it
     //here so that it always looks like an array.
-    if (data.constructor.toString().indexOf("Array") == -1) {
+    if (data.constructor.toString().indexOf("Array") === -1) {
       data = [data];
     }
     
@@ -278,7 +278,7 @@ Jaml.Template.prototype = {
     for (var i=0; i < this.nodes.length; i++) {
       var node = this.nodes[i];
       
-      if (node.parent == undefined) roots.push(node);
+      if (node.parent === undefined) roots.push(node);
     };
     
     return roots;
@@ -310,7 +310,7 @@ Jaml.Template.prototype = {
     return function(attrs) {
       var node = new Jaml.Node(tagName);
 
-      var firstArgIsAttributes =  (typeof attrs == 'object')
+      var firstArgIsAttributes =  (typeof attrs === 'object')
                                && !(attrs instanceof Jaml.Node)
                                && !(attrs instanceof Jaml.TextNode);
 
@@ -321,7 +321,7 @@ Jaml.Template.prototype = {
       for (var i=startIndex; i < arguments.length; i++) {
         var arg = arguments[i];
 
-        if (typeof arg == "string" || arg == undefined) {
+        if (typeof arg === "string" || arg === undefined) {
           arg = new Jaml.TextNode(arg || "");
         }
 

+ 2 - 1
SquiLu-ourbiz/s/ourbiz/listsearch.js

@@ -95,7 +95,8 @@ function newListSearchWindow(all_sales_buys, title, colHeaders, editWindow, dbTa
 			search_on: Jaml.render(search_on, obj_id),
 			search_on2: Jaml.render(search_on2, obj_id)
 		}
-		data.table_height = (dad.isIE && (dad.isIE == 9)) ? "20em" : "19em";
+		data.table_height = (dad.isIE ? ((dad.isIE == 9) ? "20em" : "19em") : "100%");
+		//data.table_height = (dad.isIE && (dad.isIE == 9)) ? "20em" : "19em";
 		data.data_table = Jaml.render('2TRDataTable', data);
 
 		var win = dad.newWindow(newId,220,20, 800, 500, title, Jaml.render('ListSearch', data));

+ 7 - 0
SquiLu-ourbiz/s/ourbiz/main-menu.js

@@ -1,3 +1,10 @@
+function checkNeedNewWindow(event, win)
+{
+	var evt = dad.checkEvent(event);
+	//console.log(evt.ctrlKey);
+	return evt.ctrlKey || !win
+}
+
 function newMainOrdersListSearchWindow(otype){
 	//dad.loadScript('orders.js');
 	if(window.newOrdersListSearchWindow) newOrdersListSearchWindow(otype);

+ 2 - 2
SquiLu-ourbiz/s/ourbiz/measure-units.js

@@ -1,6 +1,6 @@
 Jaml.register('MeasureUnitsListEdit', function(args) {
 	form({action: "/DB/Action", method: "post", id: args.form_id, style: "width:100%;height:100%;"},
-		table({style: "width:100%;height:100%;"},
+		table({style: "width:100%;height:100%;min-width:6em;"},
 			args.data_table,
 			tr(
 				td({'class': "editBox", style: "width:100%;"},
@@ -74,7 +74,7 @@ function newMeasureUnitsListEditWindow(){
 			table_id: table_id,
 			table_header_id: table_header_id
 		}
-		data.table_height = "50%";
+		//data.table_height = "50%";
 		data.data_table = Jaml.render('2TRDataTable', data);
 
 		var win = dad.newWindow(newId,220,20, 550, 450, _tr(title), Jaml.render('MeasureUnitsListEdit', data));

+ 1 - 1
SquiLu-ourbiz/s/ourbiz/order-types.js

@@ -132,7 +132,7 @@ function newOrderTypesListEditWindow(){
 			table_id: table_id,
 			table_header_id: table_header_id
 		}
-		data.table_height = "50%";
+		//data.table_height = "50%";
 		data.data_table = Jaml.render('2TRDataTable', data);
 
 		var win = dad.newWindow(newId,220,20, 800, 560, _tr(title), Jaml.render('OrderTypesListEdit', data));

+ 1 - 1
SquiLu-ourbiz/s/ourbiz/payment-types.js

@@ -82,7 +82,7 @@ function newPaymentTypesListEditWindow(){
 			table_id: table_id,
 			table_header_id: table_header_id
 		}
-		data.table_height = "50%";
+		//data.table_height = "50%";
 		data.data_table = Jaml.render('2TRDataTable', data);
 		
 		var win = dad.newWindow(newId,220,20, 550, 450, _tr(title), Jaml.render('PaymentTypesListEdit', data));

+ 1 - 1
SquiLu-ourbiz/s/ourbiz/sales-tax-rates.js

@@ -73,7 +73,7 @@ function newSalesTaxListEditWindow(){
 			table_id: table_id,
 			table_header_id: table_header_id
 		}
-		data.table_height = "50%";
+		//data.table_height = "100%";
 		data.data_table = Jaml.render('2TRDataTable', data);
 
 		var win = dad.newWindow(newId,220,20, 460, 420, _tr(title), Jaml.render('SalesTaxListEdit', data));

+ 1 - 1
SquiLu-ourbiz/s/ourbiz/warranty-types.js

@@ -74,7 +74,7 @@ function newWarrantyTypesListEditWindow(){
 			table_id: table_id,
 			table_header_id: table_header_id
 		}
-		data.table_height = "50%";
+		//data.table_height = "50%";
 		data.data_table = Jaml.render('2TRDataTable', data);
 
 		var win = dad.newWindow(newId,220,20, 550, 450, _tr(title), Jaml.render('WarrantyTypesListEdit', data));

+ 248 - 15
SquiLu-ourbiz/sqlite3-cc-gui.fl

@@ -1,5 +1,5 @@
 # data file for the Fltk User Interface Designer (fluid)
-version 1.0302 
+version 1.0303 
 i18n_type 1 
 i18n_include i18n_function.h 
 i18n_function _tr 
@@ -7,8 +7,8 @@ header_name {.h}
 code_name {.cxx}
 widget_class Sqlite3cc_Window {
   label SQLiteCC open
-  xywh {103 78 780 520} type Double labelsize 16 hide resizable
-  class Fl_Double_Window
+  xywh {218 131 780 520} type Double labelsize 16 resizable
+  class Fl_Double_Window visible
 } {
   Fl_Menu_Bar menuBar {open
     xywh {0 0 780 25} labelsize 16 textsize 16
@@ -25,6 +25,11 @@ widget_class Sqlite3cc_Window {
         label {Open DB}
         xywh {0 0 30 20} shortcut 0x4006f labelsize 16
       }
+      MenuItem menu_file_reopen {
+        label {Reopen DB}
+        dirty_name menu_file_reopen
+        xywh {0 0 36 21}
+      }
       MenuItem menu_file_attach {
         label {Attach DB}
         xywh {0 0 30 20} shortcut 0x40061 labelsize 16
@@ -90,10 +95,20 @@ widget_class Sqlite3cc_Window {
   Fl_Tile tile {open
     xywh {0 25 780 495}
   } {
-    Fl_Browser grid_tables {
-      dirty_name grid_tables
-      xywh {5 25 160 280} labelsize 16 textsize 16
-      class Fl_Data_Table
+    Fl_Group group_db_tables {
+      dirty_name group_db_tables open
+      xywh {5 25 160 280} labeltype NO_LABEL
+    } {
+      Fl_Browser grid_tables {
+        dirty_name grid_tables
+        xywh {5 25 160 255} labelsize 16 textsize 16 resizable
+        class Fl_Data_Table
+      }
+      Fl_Input iTablesFilter {
+        label {Filter:}
+        dirty_name iTablesFilter
+        xywh {5 280 160 25} labeltype NO_LABEL when 1
+      }
     }
     Fl_Group {} {open
       xywh {165 25 615 280}
@@ -105,7 +120,7 @@ widget_class Sqlite3cc_Window {
           xywh {165 25 615 35} box DOWN_FRAME labelsize 16
         } {
           Fl_Input iMaxRows {
-            label {Max Rows} selected
+            label {Max Rows}
             xywh {265 30 49 25} type Int labelsize 16 textsize 16
             code0 {o->value("50");}
           }
@@ -113,20 +128,69 @@ widget_class Sqlite3cc_Window {
             label Query open
             xywh {370 30 120 25} down_box BORDER_BOX labelsize 16 textsize 16
           } {
-            MenuItem {} {
+            MenuItem menu_sql_select {
               label select
+              dirty_name menu_sql_select
               xywh {0 0 36 21}
             }
-            MenuItem {} {
+            MenuItem menu_sql_insert {
               label insert
+              dirty_name menu_sql_insert
               xywh {0 0 36 21}
             }
-            MenuItem {} {
+            MenuItem menu_sql_update {
               label update
+              dirty_name menu_sql_update
               xywh {0 0 36 21}
             }
-            MenuItem {} {
+            MenuItem menu_sql_delete {
               label delete
+              dirty_name menu_sql_delete
+              xywh {0 0 36 21}
+            }
+            MenuItem menu_sql_schema_update {
+              label {schema update}
+              dirty_name menu_sql_schema_update
+              xywh {0 0 36 21}
+            }
+            MenuItem menu_sql_schema_update_norefs {
+              label {schema update norefs}
+              dirty_name menu_sql_schema_update_norefs selected
+              xywh {10 10 36 21}
+            }
+            MenuItem menu_sql_sqlite_master_update {
+              label {sqlite_master update}
+              dirty_name menu_sql_sqlite_master_update
+              xywh {0 0 36 21}
+            }
+            MenuItem menu_sql_drop_table {
+              label {drop table}
+              dirty_name menu_sql_drop_table
+              xywh {0 0 36 21}
+            }
+            MenuItem menu_sql_dump_table {
+              label {dump table}
+              dirty_name menu_sql_dump_table
+              xywh {0 0 36 21}
+            }
+            MenuItem menu_sql_create_index {
+              label {create index}
+              dirty_name menu_sql_create_index
+              xywh {0 0 36 21}
+            }
+            MenuItem menu_sql_create_trigger {
+              label {create trigger}
+              dirty_name menu_sql_create_trigger
+              xywh {0 0 36 21}
+            }
+            MenuItem menu_sql_references {
+              label references
+              dirty_name menu_sql_references
+              xywh {0 0 36 21}
+            }
+            MenuItem menu_sql_search_all_tables {
+              label {search all tables}
+              dirty_name menu_sql_search_all_tables
               xywh {0 0 36 21}
             }
           }
@@ -186,7 +250,7 @@ widget_class Sqlite3cc_Window {
       } {
         Fl_Group groupData {
           label Data open
-          xywh {0 333 780 187} labelsize 16 hide resizable
+          xywh {0 333 780 187} labelsize 16 resizable
         } {
           Fl_Browser grid_data {
             dirty_name grid_data
@@ -194,6 +258,17 @@ widget_class Sqlite3cc_Window {
             class Fl_Data_Table
           }
         }
+        Fl_Group groupRecord {
+          label Record
+          dirty_name groupRecord open
+          xywh {0 333 780 187} labelsize 16 hide
+        } {
+          Fl_Text_Editor edit_record {
+            dirty_name edit_record
+            xywh {5 333 770 185} labelsize 16 textsize 16
+            class Fl_Text_Editor_Buffered
+          }
+        }
         Fl_Group viewFields {
           label Fields open
           xywh {0 333 780 187} labelsize 16 hide
@@ -214,7 +289,7 @@ widget_class Sqlite3cc_Window {
         }
         Fl_Group viewTriggers {
           label Triggers open
-          xywh {0 333 780 187} labelsize 16
+          xywh {0 333 780 187} labelsize 16 hide
         } {
           Fl_Browser gridTriggers {
             xywh {0 333 780 187} labelsize 16 textsize 16
@@ -230,6 +305,17 @@ widget_class Sqlite3cc_Window {
             class Fl_Text_Editor_Buffered
           }
         }
+        Fl_Group groupReferences {
+          label References
+          dirty_name groupReferences open
+          xywh {0 333 780 187} labelsize 16 hide
+        } {
+          Fl_Text_Editor edit_references {
+            dirty_name edit_references
+            xywh {5 333 770 185} labelsize 16 textsize 16
+            class Fl_Text_Editor_Buffered
+          }
+        }
         Fl_Group tabDefaults {
           label Defaults open
           xywh {0 333 780 187} labelsize 16 hide
@@ -273,7 +359,7 @@ widget_class Sqlite3cc_Window {
 } 
 
 widget_class SquiLuEditWindow {
-  label {SquiLu Edit} open
+  label {SquiLu Edit}
   xywh {286 113 565 540} type Double hide resizable
   class Fl_Double_Window
 } {
@@ -312,3 +398,150 @@ widget_class SquiLuEditWindow {
     class Fl_Text_Editor_Buffered
   }
 } 
+
+widget_class CreateTableWindow {
+  label {Create Table}
+  xywh {648 270 565 455} type Double hide resizable
+  class Fl_Double_Window
+} {
+  Fl_Choice choice_database {
+    label {Database:}
+    dirty_name choice_database open
+    xywh {105 5 170 25} down_box BORDER_BOX
+  } {}
+  Fl_Input table_name {
+    label {Table:}
+    dirty_name table_name
+    xywh {330 5 230 25}
+  }
+  Fl_Browser grid_fields {
+    dirty_name grid_fields
+    xywh {5 35 425 195} labeltype NO_LABEL labelsize 16 textsize 16 resizable
+    class Fl_Data_Table
+  }
+  Fl_Button btnAddColumn {
+    label {Add Column}
+    dirty_name btnAddColumn
+    xywh {435 37 125 33} labelsize 16
+  }
+  Fl_Button btnDeleteColumn {
+    label {Delete Column}
+    dirty_name btnDeleteColumn
+    xywh {435 77 125 33} labelsize 16
+  }
+  Fl_Button btnEditColumn {
+    label {Edit Column}
+    dirty_name btnEditColumn
+    xywh {435 117 125 33} labelsize 16
+  }
+  Fl_Button btnUpColumn {
+    label Up
+    dirty_name btnUpColumn
+    xywh {435 157 125 33} labelsize 16
+  }
+  Fl_Button btnDownColumn {
+    label Down
+    dirty_name btnDownColumn
+    xywh {435 197 125 33} labelsize 16
+  }
+  Fl_Input table_constraints {
+    label {Table Constraints}
+    dirty_name table_constraints
+    xywh {5 255 555 75} type Multiline align 5
+  }
+  Fl_Group {} {open
+    xywh {5 336 554 39} box ENGRAVED_BOX labeltype NO_LABEL
+  } {
+    Fl_Button btnCheck {
+      label Check
+      dirty_name btnCheck
+      xywh {10 340 115 30} labelsize 16
+    }
+    Fl_Button btnOk {
+      label OK
+      dirty_name btnOk
+      xywh {310 340 115 30} labelsize 16
+    }
+    Fl_Button btnCancel {
+      label Cancel
+      dirty_name btnCancel
+      xywh {435 340 115 30} labelsize 16
+    }
+  }
+  Fl_Text_Editor output_editor {
+    dirty_name output_editor
+    xywh {5 382 555 71} labelsize 18 textsize 18
+    class Fl_Text_Editor_Buffered
+  }
+} 
+
+widget_class CreateTableFieldWindow {
+  label {Create/Edit Table Field}
+  xywh {665 216 330 375} type Double hide resizable
+  class Fl_Double_Window
+} {
+  Fl_Input field_name {
+    label {Name:}
+    dirty_name field_name
+    xywh {90 10 230 25}
+  }
+  Fl_Choice field_type {
+    label {Data type:}
+    dirty_name field_type open
+    xywh {90 40 230 25} down_box BORDER_BOX
+  } {}
+  Fl_Group group_constraints {
+    label Constraints
+    macro_name group_constraints open
+    xywh {5 90 320 240} box ENGRAVED_BOX align 5
+  } {
+    Fl_Check_Button field_primary_key {
+      label {Primary Key}
+      dirty_name field_primary_key
+      xywh {10 95 110 25} down_box DOWN_BOX
+    }
+    Fl_Check_Button field_unique {
+      label Unique
+      dirty_name field_unique
+      xywh {10 120 110 25} down_box DOWN_BOX
+    }
+    Fl_Check_Button field_not_null {
+      label {Not Null}
+      dirty_name field_not_null
+      xywh {10 145 110 25} down_box DOWN_BOX
+    }
+    Fl_Check_Button field_default {
+      label Default
+      dirty_name field_default
+      xywh {10 170 110 25} down_box DOWN_BOX
+    }
+    Fl_Input field_default_value {
+      dirty_name field_default_value
+      xywh {85 170 230 25} labeltype NO_LABEL
+    }
+    Fl_Input field_check {
+      label {Check:}
+      dirty_name field_check
+      xywh {85 200 230 25}
+    }
+    Fl_Choice field_collate {
+      label {Collate:}
+      dirty_name field_collate open
+      xywh {85 230 230 25} down_box BORDER_BOX
+    } {}
+  }
+  Fl_Group {} {open
+    xywh {5 336 320 39} box ENGRAVED_BOX labeltype NO_LABEL
+  } {
+    Fl_Button btnOk {
+      label OK
+      dirty_name btnOk
+      xywh {10 340 115 30} labelsize 16
+    }
+    Fl_Button btnCancel {
+      label Cancel
+      dirty_name btnCancel
+      xywh {205 340 115 30} labelsize 16
+    }
+  }
+} 

+ 333 - 64
SquiLu-ourbiz/sqlite3-cc-gui.nut

@@ -1,57 +1,77 @@
 class Sqlite3cc_Window extends Fl_Double_Window {
   
   // Declaration of class members
-  menuBar = null;
-  menu_file_new = null;
-  menu_file_open = null;
-  menu_file_attach = null;
-  menu_file_close = null;
-  menu_file_execute = null;
-  menu_file_exit = null;
-  menu_settings_encoding = null;
-  menu_settings_preferences = null;
-  menu_help_about = null;
-  menu_squilu_edit = null;
-  tile = null;
-  grid_tables = null;
-  group_sql = null;
-  group_buttons = null;
-  iMaxRows = null;
-  option_query = null;
-  btnCreateQuery = null;
-  btnExecute = null;
-  btnLoad = null;
-  btnSave = null;
-  edit_queries = null;
-  group_log = null;
-  tabsLog = null;
-  groupMessages = null;
-  output_messages = null;
-  groupHistory = null;
-  browser_history = null;
-  group_bottom = null;
-  tabView = null;
-  groupData = null;
-  grid_data = null;
-  viewFields = null;
-  grid_fields = null;
-  viewIndexes = null;
-  gridIndexes = null;
-  viewTriggers = null;
-  gridTriggers = null;
-  groupSchema = null;
-  edit_schema = null;
-  tabDefaults = null;
-  iDefaultHash = null;
-  iDefaultRubyStyle = null;
-  iDefaultWithNL = null;
-  iDefaultFieldPrefix = null;
-  iDefaultFieldSufix = null;
-  iDefaultStrip = null;
-  iDefaultEscapeSQL = null;
-  iDefaultFieldConvert = null;
+  menuBar : Fl_Menu_Bar;
+  menu_file_new : Submenu;
+  menu_file_open : Submenu;
+  menu_file_reopen : Submenu;
+  menu_file_attach : Submenu;
+  menu_file_close : Submenu;
+  menu_file_execute : Submenu;
+  menu_file_exit : Submenu;
+  menu_settings_encoding : Submenu;
+  menu_settings_preferences : Submenu;
+  menu_help_about : Submenu;
+  menu_squilu_edit : Submenu;
+  tile : Fl_Tile;
+  group_db_tables : Fl_Group;
+  grid_tables : Fl_Data_Table;
+  iTablesFilter : Fl_Input;
+  group_sql : Fl_Group;
+  group_buttons : Fl_Group;
+  iMaxRows : Fl_Input;
+  option_query : Fl_Choice;
+  menu_sql_select : MenuItem;
+  menu_sql_insert : MenuItem;
+  menu_sql_update : MenuItem;
+  menu_sql_delete : MenuItem;
+  menu_sql_schema_update : MenuItem;
+  menu_sql_schema_update_norefs : MenuItem;
+  menu_sql_sqlite_master_update : MenuItem;
+  menu_sql_drop_table : MenuItem;
+  menu_sql_dump_table : MenuItem;
+  menu_sql_create_index : MenuItem;
+  menu_sql_create_trigger : MenuItem;
+  menu_sql_references : MenuItem;
+  menu_sql_search_all_tables : MenuItem;
+  btnCreateQuery : Fl_Button;
+  btnExecute : Fl_Button;
+  btnLoad : Fl_Button;
+  btnSave : Fl_Button;
+  edit_queries : Fl_Text_Editor_Buffered;
+  group_log : Fl_Group;
+  tabsLog : Fl_Tabs;
+  groupMessages : Fl_Group;
+  output_messages : Fl_Output;
+  groupHistory : Fl_Group;
+  browser_history : Fl_Browser;
+  group_bottom : Fl_Group;
+  tabView : Fl_Tabs;
+  groupData : Fl_Group;
+  grid_data : Fl_Data_Table;
+  groupRecord : Fl_Group;
+  edit_record : Fl_Text_Editor_Buffered;
+  viewFields : Fl_Group;
+  grid_fields : Fl_Data_Table;
+  viewIndexes : Fl_Group;
+  gridIndexes : Fl_Data_Table;
+  viewTriggers : Fl_Group;
+  gridTriggers : Fl_Data_Table;
+  groupSchema : Fl_Group;
+  edit_schema : Fl_Text_Editor_Buffered;
+  groupReferences : Fl_Group;
+  edit_references : Fl_Text_Editor_Buffered;
+  tabDefaults : Fl_Group;
+  iDefaultHash : Fl_Input;
+  iDefaultRubyStyle : Fl_Check_Button;
+  iDefaultWithNL : Fl_Check_Button;
+  iDefaultFieldPrefix : Fl_Input;
+  iDefaultFieldSufix : Fl_Input;
+  iDefaultStrip : Fl_Check_Button;
+  iDefaultEscapeSQL : Fl_Check_Button;
+  iDefaultFieldConvert : Fl_Check_Button;
   
-  constructor(px=103, py=78, pw=780, ph=520, pl=_tr("SQLiteCC")){
+  constructor(px=218, py=131, pw=780, ph=520, pl=_tr("SQLiteCC")){
     base.constructor(px, py, pw, ph, pl);
     // Create member functions and widgets
     {
@@ -63,6 +83,7 @@ class Sqlite3cc_Window extends Fl_Double_Window {
         //menu_file File
         menu_file_new = o.add(_tr("File/New DB"), 262254);
         menu_file_open = o.add(_tr("File/Open DB"), 0);
+        menu_file_reopen = o.add(_tr("File/Reopen DB"), 0);
         menu_file_attach = o.add(_tr("File/Attach DB"), 0);
         menu_file_close = o.add(_tr("File/Close DB"), 0, null, null, 128);
         menu_file_execute = o.add(_tr("File/Execute"), 0, null, null, 128);
@@ -84,10 +105,25 @@ class Sqlite3cc_Window extends Fl_Double_Window {
       tile = o;
       {
         {
-          local o = Fl_Data_Table(5, 25, 160, 280);
-          grid_tables = o;
-          o.textsize(16);
-          o.labelsize(16);
+          local o = Fl_Group(5, 25, 160, 280);
+          group_db_tables = o;
+          o.labeltype(FL_NO_LABEL);
+          {
+            {
+              local o = Fl_Data_Table(5, 25, 160, 255);
+              grid_tables = o;
+              o.textsize(16);
+              o.labelsize(16);
+              o.end();
+              Fl_Group.current().resizable(o);
+            }
+            {
+              local o = Fl_Input(5, 280, 160, 25, _tr("Filter:"));
+              iTablesFilter = o;
+              o.labeltype(FL_NO_LABEL);
+              o.when(1);
+            }
+          }
           o.end();
         }
         {
@@ -120,10 +156,19 @@ class Sqlite3cc_Window extends Fl_Double_Window {
                       o.labelsize(16);
                       o.down_box(FL_BORDER_BOX);
                       {
-                        o.add(_tr("select"), 0);
-                        o.add(_tr("insert"), 0);
-                        o.add(_tr("update"), 0);
-                        o.add(_tr("delete"), 0);
+                        menu_sql_select = o.add(_tr("select"), 0);
+                        menu_sql_insert = o.add(_tr("insert"), 0);
+                        menu_sql_update = o.add(_tr("update"), 0);
+                        menu_sql_delete = o.add(_tr("delete"), 0);
+                        menu_sql_schema_update = o.add(_tr("schema update"), 0);
+                        menu_sql_schema_update_norefs = o.add(_tr("schema update norefs"), 0);
+                        menu_sql_sqlite_master_update = o.add(_tr("sqlite_master update"), 0);
+                        menu_sql_drop_table = o.add(_tr("drop table"), 0);
+                        menu_sql_dump_table = o.add(_tr("dump table"), 0);
+                        menu_sql_create_index = o.add(_tr("create index"), 0);
+                        menu_sql_create_trigger = o.add(_tr("create trigger"), 0);
+                        menu_sql_references = o.add(_tr("references"), 0);
+                        menu_sql_search_all_tables = o.add(_tr("search all tables"), 0);
                       }
                     }
                     {
@@ -240,6 +285,20 @@ class Sqlite3cc_Window extends Fl_Double_Window {
                   o.end();
                   Fl_Group.current().resizable(o);
                 }
+                {
+                  local o = Fl_Group(0, 333, 780, 187, _tr("Record"));
+                  groupRecord = o;
+                  o.labelsize(16);
+                  {
+                    {
+                      local o = Fl_Text_Editor_Buffered(5, 333, 770, 185);
+                      edit_record = o;
+                      o.textsize(16);
+                      o.labelsize(16);
+                    }
+                  }
+                  o.end();
+                }
                 {
                   local o = Fl_Group(0, 333, 780, 187, _tr("Fields"));
                   viewFields = o;
@@ -299,6 +358,20 @@ class Sqlite3cc_Window extends Fl_Double_Window {
                   }
                   o.end();
                 }
+                {
+                  local o = Fl_Group(0, 333, 780, 187, _tr("References"));
+                  groupReferences = o;
+                  o.labelsize(16);
+                  {
+                    {
+                      local o = Fl_Text_Editor_Buffered(5, 333, 770, 185);
+                      edit_references = o;
+                      o.textsize(16);
+                      o.labelsize(16);
+                    }
+                  }
+                  o.end();
+                }
                 {
                   local o = Fl_Group(0, 333, 780, 187, _tr("Defaults"));
                   tabDefaults = o;
@@ -365,18 +438,19 @@ class Sqlite3cc_Window extends Fl_Double_Window {
       }
       o.end();
     }
+    end();
   }
 }
 
 class SquiLuEditWindow extends Fl_Double_Window {
   
   // Declaration of class members
-  code_editor = null;
-  words_to_search = null;
-  btnSearch = null;
-  btnSavehelp = null;
-  btnRun = null;
-  output_editor = null;
+  code_editor : Fl_Text_Editor_Buffered;
+  words_to_search : Fl_Input;
+  btnSearch : Fl_Button;
+  btnSavehelp : Fl_Button;
+  btnRun : Fl_Button;
+  output_editor : Fl_Text_Editor_Buffered;
   
   constructor(px=286, py=113, pw=565, ph=540, pl=_tr("SquiLu Edit")){
     base.constructor(px, py, pw, ph, pl);
@@ -423,6 +497,201 @@ class SquiLuEditWindow extends Fl_Double_Window {
       o.labelsize(18);
       Fl_Group.current().resizable(o);
     }
+    end();
+  }
+}
+
+class CreateTableWindow extends Fl_Double_Window {
+  
+  // Declaration of class members
+  choice_database : Fl_Choice;
+  table_name : Fl_Input;
+  grid_fields : Fl_Data_Table;
+  btnAddColumn : Fl_Button;
+  btnDeleteColumn : Fl_Button;
+  btnEditColumn : Fl_Button;
+  btnUpColumn : Fl_Button;
+  btnDownColumn : Fl_Button;
+  table_constraints : Fl_Input;
+  btnCheck : Fl_Button;
+  btnOk : Fl_Button;
+  btnCancel : Fl_Button;
+  output_editor : Fl_Text_Editor_Buffered;
+  
+  constructor(px=648, py=270, pw=565, ph=455, pl=_tr("Create Table")){
+    base.constructor(px, py, pw, ph, pl);
+    // Create member functions and widgets
+    {
+      local o = Fl_Choice(105, 5, 170, 25, _tr("Database:"));
+      choice_database = o;
+      o.down_box(FL_BORDER_BOX);
+    }
+    {
+      local o = Fl_Input(330, 5, 230, 25, _tr("Table:"));
+      table_name = o;
+    }
+    {
+      local o = Fl_Data_Table(5, 35, 425, 195);
+      grid_fields = o;
+      o.textsize(16);
+      o.labeltype(FL_NO_LABEL);
+      o.labelsize(16);
+      o.end();
+      Fl_Group.current().resizable(o);
+    }
+    {
+      local o = Fl_Button(435, 37, 125, 33, _tr("Add Column"));
+      btnAddColumn = o;
+      o.labelsize(16);
+    }
+    {
+      local o = Fl_Button(435, 77, 125, 33, _tr("Delete Column"));
+      btnDeleteColumn = o;
+      o.labelsize(16);
+    }
+    {
+      local o = Fl_Button(435, 117, 125, 33, _tr("Edit Column"));
+      btnEditColumn = o;
+      o.labelsize(16);
+    }
+    {
+      local o = Fl_Button(435, 157, 125, 33, _tr("Up"));
+      btnUpColumn = o;
+      o.labelsize(16);
+    }
+    {
+      local o = Fl_Button(435, 197, 125, 33, _tr("Down"));
+      btnDownColumn = o;
+      o.labelsize(16);
+    }
+    {
+      local o = Fl_Multiline_Input(5, 255, 555, 75, _tr("Table Constraints"));
+      table_constraints = o;
+      o.align(5);
+    }
+    {
+      local o = Fl_Group(5, 336, 554, 39);
+      o.box(FL_ENGRAVED_BOX);
+      o.labeltype(FL_NO_LABEL);
+      {
+        {
+          local o = Fl_Button(10, 340, 115, 30, _tr("Check"));
+          btnCheck = o;
+          o.labelsize(16);
+        }
+        {
+          local o = Fl_Button(310, 340, 115, 30, _tr("OK"));
+          btnOk = o;
+          o.labelsize(16);
+        }
+        {
+          local o = Fl_Button(435, 340, 115, 30, _tr("Cancel"));
+          btnCancel = o;
+          o.labelsize(16);
+        }
+      }
+      o.end();
+    }
+    {
+      local o = Fl_Text_Editor_Buffered(5, 382, 555, 71);
+      output_editor = o;
+      o.textsize(18);
+      o.labelsize(18);
+    }
+    end();
+  }
+}
+
+class CreateTableFieldWindow extends Fl_Double_Window {
+  
+  // Declaration of class members
+  field_name : Fl_Input;
+  field_type : Fl_Choice;
+  group_constraints : Fl_Group;
+  field_primary_key : Fl_Check_Button;
+  field_unique : Fl_Check_Button;
+  field_not_null : Fl_Check_Button;
+  field_default : Fl_Check_Button;
+  field_default_value : Fl_Input;
+  field_check : Fl_Input;
+  field_collate : Fl_Choice;
+  btnOk : Fl_Button;
+  btnCancel : Fl_Button;
+  
+  constructor(px=665, py=216, pw=330, ph=375, pl=_tr("Create/Edit Table Field")){
+    base.constructor(px, py, pw, ph, pl);
+    // Create member functions and widgets
+    {
+      local o = Fl_Input(90, 10, 230, 25, _tr("Name:"));
+      field_name = o;
+    }
+    {
+      local o = Fl_Choice(90, 40, 230, 25, _tr("Data type:"));
+      field_type = o;
+      o.down_box(FL_BORDER_BOX);
+    }
+    {
+      local o = Fl_Group(5, 90, 320, 240, _tr("Constraints"));
+      group_constraints = o;
+      o.box(FL_ENGRAVED_BOX);
+      o.align(5);
+      {
+        {
+          local o = Fl_Check_Button(10, 95, 110, 25, _tr("Primary Key"));
+          field_primary_key = o;
+          o.down_box(FL_DOWN_BOX);
+        }
+        {
+          local o = Fl_Check_Button(10, 120, 110, 25, _tr("Unique"));
+          field_unique = o;
+          o.down_box(FL_DOWN_BOX);
+        }
+        {
+          local o = Fl_Check_Button(10, 145, 110, 25, _tr("Not Null"));
+          field_not_null = o;
+          o.down_box(FL_DOWN_BOX);
+        }
+        {
+          local o = Fl_Check_Button(10, 170, 110, 25, _tr("Default"));
+          field_default = o;
+          o.down_box(FL_DOWN_BOX);
+        }
+        {
+          local o = Fl_Input(85, 170, 230, 25);
+          field_default_value = o;
+          o.labeltype(FL_NO_LABEL);
+        }
+        {
+          local o = Fl_Input(85, 200, 230, 25, _tr("Check:"));
+          field_check = o;
+        }
+        {
+          local o = Fl_Choice(85, 230, 230, 25, _tr("Collate:"));
+          field_collate = o;
+          o.down_box(FL_BORDER_BOX);
+        }
+      }
+      o.end();
+    }
+    {
+      local o = Fl_Group(5, 336, 320, 39);
+      o.box(FL_ENGRAVED_BOX);
+      o.labeltype(FL_NO_LABEL);
+      {
+        {
+          local o = Fl_Button(10, 340, 115, 30, _tr("OK"));
+          btnOk = o;
+          o.labelsize(16);
+        }
+        {
+          local o = Fl_Button(205, 340, 115, 30, _tr("Cancel"));
+          btnCancel = o;
+          o.labelsize(16);
+        }
+      }
+      o.end();
+    }
+    end();
   }
 }
 

+ 709 - 37
SquiLu-ourbiz/sqlite3-cc.nut

@@ -1,3 +1,4 @@
+#!/home/mingo/bin/squilu
 /*
  * Copyright (C) 2013 by Domingo Alvarez Duarte <[email protected]>
  *
@@ -37,11 +38,16 @@ class Fl_Data_Table extends Flv_Data_Table {
 	}
 
 	function clear_data_rows(){
+		col(0);
+		cols(0);
 		row(0);
 		rows(0);
 		_data.clear();
 	}
 	function recalc_data(){
+		col(0);
+		row(0);
+		rows(0);
 		rows(_data.size());
 		redraw();
 	}
@@ -140,10 +146,12 @@ class Fl_Data_Table extends Flv_Data_Table {
 		switch(event){
 			case FL_RELEASE:{
 				local done = false;
-				if(Fl.event_clicks() > 0){
+				local clicks = Fl.event_clicks();
+				if(clicks > 0){
 					row_selected(Fl_Data_Table_Events.e_update);
 					done = true;
 				}
+				else row_changed();
 				if(done){
 					Fl.event_clicks(0);
 					return 1;
@@ -177,6 +185,7 @@ class Fl_Data_Table extends Flv_Data_Table {
 		return rc;
 	}
 	function row_selected(ev){ if(_call_this) _call_this.row_selected(this, ev);}
+	function row_changed(){ if(_call_this) _call_this.row_changed(this);}
 	function set_cols(mycols, size_absolute=false){
 		_cols_info.clear();
 		for(local i=0, max_cols=mycols.size(); i < max_cols; ++i){
@@ -270,18 +279,224 @@ class Fl_Data_Table extends Flv_Data_Table {
 	}
 	function clear_selection(){
 	}
+	function get_col_name(idx){
+		return _cols_info[idx].colname;
+	}
+	function get_row(arow=null){
+		if(arow == null) arow = row();
+		return _data.len() ? _data[arow] : null;
+	}
 	function get_row_id(arow=null){
 		if(arow == null) arow = row();
-		return _data[arow][0].tointeger();
+		return _data.len() ? _data[arow][0].tointeger() : 0;
+	}
+	function get_row_field_by_name(field_name, arow=null){
+		if(arow == null) arow = row();
+		foreach(idx, ci in _cols_info)
+		{
+			if(ci.colname == field_name)
+			{
+				return _data.len() ? _data[arow][idx] : null;
+			}
+		}
+		return null;
+	}
+	function select_row_by_id(the_id){
+		for(local i=0, len=_data.len(); i < len; ++i)
+		{
+			if(_data[i][0] == the_id)
+			{
+				row(i);
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	function delete_row_id(arow=null)
+	{
+		if(arow == null) arow = row();
+		_data.remove(arow);
+		recalc_data();
 	}
 }
 
 dofile("sqlite3-cc-gui.nut", false, false);
 
+function create_stmt_bind(db, sql, bind_values=null)
+{
+	local result = false;
+	local stmt = db.prepare(sql);
+	if(bind_values)
+	{
+		foreach(k,v in bind_values)
+		{
+			stmt.bind(k+1, v);
+		}
+	}
+	return stmt;
+}
+
+function exec_get_all(db, sql, bind_values=null)
+{
+	local stmt = create_stmt_bind(db, sql, bind_values);
+	local result = stmt.asArrayOfTables();
+	stmt.finalize();
+	return result;
+}
+
+function exec_get_one(db, sql, bind_values=null)
+{
+	local result = null;
+	local stmt = create_stmt_bind(db, sql, bind_values);
+	if(stmt.next_row())
+	{
+		result = stmt.col(0);
+	}
+	stmt.finalize();
+	return result;
+}
+
+function exec_dml(db, sql, bind_values=null)
+{
+	local stmt = create_stmt_bind(db, sql, bind_values);
+	local result = stmt.step() == stmt.SQLITE_DONE;
+	stmt.finalize();
+	return result;
+}
+
+local function sanitizeDBName(dbname)
+{
+	return dbname.gsub("([^_%-a-zA-Z0-9])","");
+}
+
+local function escapeRE(str)
+{
+	return str.gsub("(%-)", "%%%1");
+}
+
+function getReferencesOnDBSchema(db, name)
+{
+	local reference_name = escapeRE(sanitizeDBName(name));
+	local prefix_suffix_re = "[%s%(%),%.<>!=%-%+%*/\"']";
+	local reference_name_re = prefix_suffix_re + "(" + reference_name + ")" + prefix_suffix_re;
+	local reference_re = "()" + reference_name + "()";
+	//print(reference_re);
+
+	local checkValidRefenceName = function(whole_str, start_idx, end_idx)
+	{
+		//!!!this assume that the name searched is not at the begning or end of whole_str
+		local context = whole_str.slice( (start_idx ? start_idx-1 : start_idx) , 
+								(end_idx < whole_str.len() ? end_idx+1 : end_idx) );
+		if(context.match(reference_name_re))
+		{
+			if( (context[0] == '\'') && (context[context.len()-1] != '\'') ) return false;
+			else if( (context[0] == '"') && (context[context.len()-1] != '"') ) return false;
+			return true;
+		}
+		return false;
+	}
+
+	local result = blob(0, 8192);
+	local stmt = db.prepare("SELECT type, name, sql FROM sqlite_master;");
+	while(stmt.next_row())
+	{
+		local sql = stmt.col(2);
+		if((::type(sql) == "string"))
+		{
+			sql = sql.tolower();
+			sql.gmatch(reference_re, function(start_idx, end_idx){
+					//print(start_idx, end_idx, sql.slice(start_idx, end_idx));
+					if(checkValidRefenceName(sql, start_idx, end_idx))
+					{
+						//print("idx", start_idx, end_idx, sql.slice(start_idx, end_idx));
+						//print(sql);
+						result.write("-------------\n");
+						result.write(stmt.col(0), "\t", stmt.col(1), "\n");
+						result.write(stmt.col(2), "\n");
+						return false; //one match is enough
+					}
+					return true;
+				});
+		}
+	}
+	stmt.finalize();
+
+	return result.tostring();
+}
+
+local function searchOnAllTables(db, search_str, search_limit)
+{
+	local embedded_limit = search_str.match("^(%d+):");
+	if(embedded_limit)
+	{
+		search_limit = embedded_limit.tointeger();
+		search_str = search_str.match("^%d+:(.+)");
+	}
+	local the_search_str;
+	if( search_str.match("^_re_:") )
+	{
+		the_search_str = search_str.match("^_re_:(.+)");
+	}
+	else the_search_str = escapeRE(search_str);
+	the_search_str = the_search_str.tolower();
+	local search_count = 0;
+	local result = blob(0, 8192);
+	local stmt = db.prepare("SELECT name FROM sqlite_master WHERE type='table';");
+	while(stmt.next_row())
+	{
+		local tbl_name = stmt.col(0);
+		local tbl_stmt = db.prepare("SELECT * FROM \"" + tbl_name + "\"");
+		local col_count = tbl_stmt.col_count();
+		local text_cols = [];
+		for(local i=0; i < col_count; ++i)
+		{
+			local dtype = tbl_stmt.col_declared_type(i).tolower();
+			if( (dtype.indexOf("varchar") >= 0) || (dtype.indexOf("text") >= 0) ) text_cols.push(i);
+		}
+		if(text_cols.len())
+		{
+			local text_cols_len = text_cols.len();
+			local tbl_done = false;
+			while(tbl_stmt.next_row() && !tbl_done)
+			{
+				for(local i=0; i < text_cols_len; ++i)
+				{
+					local col_idx = text_cols[i];
+					local str = tbl_stmt.col(col_idx);
+					if((::type(str) == "string"))
+					{
+						if(str.tolower().match(the_search_str))
+						{
+							result.write(tbl_name, ":", tbl_stmt.col_name(col_idx), "\n");
+							++search_count;
+							tbl_done = true;
+							break;
+						}
+					}
+				}
+			}
+		}
+		tbl_stmt.finalize();
+		
+		if(search_count >= search_limit) break;
+	}
+	stmt.finalize();
+
+	return result.tostring();
+}
+
+local function multiply3(ctx,a,b,c){
+	//print(ctx.user_data());
+	ctx.result_double(a*b*c);
+}
+
 class Sqlite3CC extends Sqlite3cc_Window {
   
 	// Declaration of class members
 	db_file_name = null;
+	_the_schema_version = null;
+	_my_tables_data = null;
 	label_title = null;
 	db = null;
 	attached_databases = null;
@@ -292,17 +507,147 @@ class Sqlite3CC extends Sqlite3cc_Window {
 		menuBar.callback(menuBar_cb);
 		btnExecute.callback(btnExecute_cb);
 		btnCreateQuery.callback(btnCreateQuery_cb);
-		grid_tables._call_this = this;
+		tabView.callback(tabView_cb);
+		grid_tables._call_this = this.weakref();
+		grid_data._call_this = this.weakref();
+		local last_db_file_name = Fl.preferences_get("last_db_file_name", "");
+		openDB(last_db_file_name);
+		iTablesFilter.callback(doDataSearch_cb);
+	}
+	
+	function doDataSearch_cb(sender : Fl_Widget, udata : any)
+	{
+		this = sender->window();
+		local filtered_data = doFilterMyData(iTablesFilter->value(), grid_tables->_data);
+		grid_tables->set_data(filtered_data);
+	}
+	
+	function doFilterMyData(value, prev_filtered_data)
+	{
+		local the_data = prev_filtered_data;
+		local value_len = value.len();
+		//print(__LINE__, _my_tables_data.len(), the_data.len(), value.len(), value);
+		if(value_len == 0) return _my_tables_data;
+		
+		if(value_len == 1 || the_data.len() == 0)
+		{
+			//we start from scratch
+			the_data = _my_tables_data;
+		}
+		local filtered_data = [];
+		foreach(rec in the_data)
+		{
+			foreach(field in rec)
+			{
+				if(field)
+				{
+					local fs = field.tostring();
+					if(fs.len() && fs.tostring().indexOf(value) >= 0)
+					{
+						filtered_data.push(rec);
+						break;
+					}
+				}
+			}
+		}
+		return filtered_data;
+	}
+	
+	function getSchemaVersion()
+	{
+		return db.exec_get_one("PRAGMA schema_version");
+	}
+	
+	function checkSchemaVersion()
+	{
+		if(_the_schema_version != getSchemaVersion())
+		{
+			local tables_idx = grid_tables->row();
+			get_tables();
+			local v = iTablesFilter->value();
+			if(v.len())
+			{
+				doDataSearch_cb(iTablesFilter, null);
+			}
+			grid_tables->row(tables_idx < grid_tables->rows() ? tables_idx : grid_tables->rows()-1);
+		}
+	}
+
+	function getSchemaSqlFor(tbl)
+	{
+		local str = format("SELECT sql FROM sqlite_master WHERE (type='table' OR type='view') AND tbl_name='%s'", tbl);
+		return str;
+	}
+	function getSchemaFor(tbl)
+	{
+		local str = db.exec_get_one(getSchemaSqlFor(tbl));
+		return str;
+	}
+	
+	function getIndexesSqlFor(tbl)
+	{
+		local str = format("SELECT name, sql FROM sqlite_master WHERE type='index' AND tbl_name='%s' ORDER BY name;", tbl);
+		return str;
+	}
+	
+	function getTriggersSqlFor(tbl)
+	{
+		local str = format("SELECT name, sql FROM sqlite_master WHERE type='trigger' AND tbl_name='%s' ORDER BY name;", tbl);
+		return str;
+	}
+	
+	function getFieldsFor(tbl)
+	{
+		local stmt = db.prepare("select * from \"" + tbl + "\"");
+		local fields = stmt.colsAsArray();
+		stmt.finalize();
+		return fields;
+	}
+
+	function getFieldsAsCSVFor(tbl)
+	{
+		local fields = getFieldsFor(tbl);
+		local str_fields =  "\"" + fields.concat("\", \"") + "\"";
+		return str_fields;
+	}
+	
+	function showExecutionTime(start_time)
+	{
+		local end_time = os.clock();
+		output_messages->value("Execution time = " + (end_time - start_time) + " seconds");
+		tabsLog->value(groupMessages);
+	}
+
+	function row_changed(sender)
+	{
+		if(sender == grid_tables){
+			local tbl = grid_tables.get_value(grid_tables.row(), 1);
+			refreshTabView(tbl); 
+		}
 	}
 	
 	function row_selected(sender, ev){
-		if(sender == grid_tables, ev){
+		if(sender == grid_tables){
 			if(ev == Fl_Data_Table_Events.e_update){
 				local tbl = grid_tables.get_value(grid_tables.row(), 1);
-				local sql = "select * from " + tbl;
+				local sql = "select * from \"" + tbl + "\"";
 				local limit = iMaxRows.value();
 				if(limit && limit.len()) sql += " limit " + limit;
+				local start_time = os.clock();
 				get_records_by_sql(grid_data, sql, true);
+				showExecutionTime(start_time);
+				tabView->value(groupData);
+			}
+		}
+		else if(sender == grid_data){
+			if(ev == Fl_Data_Table_Events.e_update){
+				local row = grid_data.get_row();
+				local record = blob(0, 8192);
+				foreach(idx, val in row)
+					record.write((idx ? "\n" : ""), "----", idx, ":", 
+						grid_data.get_col_name(idx),"\n", val);
+				edit_record.value(record.tostring());
+				tabView->value(groupRecord);
 			}
 		}
 	}
@@ -310,7 +655,101 @@ class Sqlite3CC extends Sqlite3cc_Window {
 	function btnExecute_cb(sender, udata){
 		this = sender->window();
 		local sql = edit_queries->value();
-		if(sql && sql.len()) get_records_by_sql(grid_data, sql, true);
+		if(sql && sql.len()) {
+			local start_time;
+			local action = option_query.text();
+			local foreign_keys_saved = null;
+			switch(action)
+			{
+				case "references":
+					local references = getReferencesOnDBSchema(db, sql);
+					edit_references->value(references);
+					tabView->value(groupReferences);
+				break;
+
+				case "search all tables":
+					local references = searchOnAllTables(db, sql, iMaxRows->value().tointeger());
+					edit_references->value(references);
+					tabView->value(groupReferences);
+				break;
+
+				case "schema update":
+				case "schema update norefs":
+					foreign_keys_saved = db.exec_get_one("PRAGMA foreign_keys");
+				case "insert":
+				case "update":
+				case "delete":
+				case "create index":
+				case "create trigger":
+				case "sqlite_master update":
+				case "drop table":
+					try
+					{
+						start_time = os.clock();
+						sql = edit_queries->value();
+
+						db.exec_dml(sql);
+
+						showExecutionTime(start_time);
+
+						switch(action)
+						{
+							case "create index":
+							case "create trigger":
+							case "schema update":
+							case "schema update norefs":
+							case "sqlite_master update":
+							case "drop table":
+								checkSchemaVersion();
+							break;
+						}						
+					}
+					catch(e)
+					{
+						if(!db.IsAutoCommitOn() || (action == "schema update")) db.exec_dml("ROLLBACK;");
+						if(foreign_keys_saved != null) db.exec_dml("PRAGMA foreign_keys=" + foreign_keys_saved);
+						fl_alert(e);
+					}
+				break;
+				
+				case "dump table":
+				break;
+
+				default:
+					try
+					{
+						start_time = os.clock();
+						get_records_by_sql(grid_data, sql, true);
+						showExecutionTime(start_time);
+						tabView->value(groupData);
+						checkSchemaVersion();
+					}
+					catch(e)
+					{
+						if(!db.IsAutoCommitOn()) db.exec_dml("ROLLBACK;");
+						fl_alert(e);
+					}
+			}
+		}
+	}
+	
+	function getIndexesAndTriggersFor(tbl, result)
+	{
+		local stmt = db.prepare(getIndexesSqlFor(tbl));
+		while(stmt.next_row())
+		{
+			local str = stmt.col(1);
+			if(::type(str) == "string") result.write("\n\n", str, ";");
+		}
+		stmt.finalize();
+
+		stmt = db.prepare(getTriggersSqlFor(tbl));
+		while(stmt.next_row())
+		{
+			local str = stmt.col(1);
+			if(::type(str) == "string") result.write("\n\n", str, ";");
+		}
+		stmt.finalize();
 	}
   
 	function btnCreateQuery_cb(sender, udata){
@@ -318,21 +757,225 @@ class Sqlite3CC extends Sqlite3cc_Window {
 		if(db){
 			local tbl = grid_tables.get_value(grid_tables.row(), 1);
 			local sql = option_query.text();
-			local stmt = db.prepare("select * from " + tbl);
-			local fields = stmt.colsAsArray();
-			local str_fields =  fields.concat(", ");
-			stmt.finalize();
-			if(sql == "select") sql = format("select %s\nfrom %s", str_fields, tbl);
-			else if(sql == "insert") sql = format("insert into %s(%s)\nvalues(%s)", tbl, str_fields, str_fields);
+			local fields = getFieldsFor(tbl);
+			local fields_csv = "\"" + fields.concat("\", \"") + "\"";
+			
+			local genSchemaUpgrade = function(with_references)
+			{
+				local new_suffix = "___new";
+				local old_suffix = "";
+				local result = blob(0, 8192);
+				result.write("PRAGMA foreign_keys=OFF;\n\nBEGIN;\n\n");
+				local str_schema = getSchemaFor(tbl);
+				str_schema = str_schema.gsub("(" + escapeRE(tbl) + ")", "%1" + new_suffix, 1);
+				str_schema = str_schema.gsub("\n%s+", "\n\t");
+				result.write(str_schema, ";");
+				fields_csv = fields_csv.gsub(", ", ",\n\t");
+				result.write(format("\n\nINSERT INTO %s%s(\n\t%s\n\t)\nSELECT\n\t%s\nFROM \"%s%s\";", tbl, new_suffix, fields_csv, fields_csv, tbl, old_suffix));
+				result.write("\n\nDROP TABLE \"", tbl, old_suffix, "\";");
+				result.write("\n\nALTER TABLE \"", tbl, new_suffix, "\" RENAME TO \"", tbl, old_suffix, "\";");
+				
+				getIndexesAndTriggersFor(tbl, result);
+				
+				if(with_references)
+				{
+					result.write("\n\nDROP VIEW \"view_name\";\n\n");
+					result.write(getReferencesOnDBSchema(db, tbl));
+					result.write("\n\nCREATE VIEW  \"view_name\"  AS \"db_table_name\";");
+				}
+				result.write("\n\nPRAGMA foreign_key_check;\n\nCOMMIT;\n\nPRAGMA foreign_keys=ON;");
+				return result.tostring();
+			};
+			
+			if(sql == "select")
+			{
+				local alias_letter = 'a';
+				local myjoins = "";
+				local fields_last_idx = fields.len()-1;
+
+				local stmt = db.prepare(format("PRAGMA foreign_key_list(\"%s\")", tbl));
+				local last_fk_id = -1;
+				while(stmt.next_row())
+				{
+					local fk_id = stmt.col(0);
+					local ftable = stmt.col(2);
+					local ffrom = stmt.col(3);
+					local fto = stmt.col(4);
+					local field_idx = fields.find(ffrom);
+					local is_new_join = last_fk_id != fk_id;
+					if(is_new_join) ++alias_letter;
+					if(field_idx)
+					{
+						fields[field_idx] += format("\"%s --%c.\"%s", (fields_last_idx == field_idx ? "" : ","), alias_letter, fto);
+					}
+					if(is_new_join)
+					{
+						myjoins += format("\n--LEFT JOIN \"%s\" AS %c ON a.\"%s\" = %c.\"%s\"", ftable, alias_letter, ffrom, alias_letter, fto);
+					}
+					else
+					{
+						myjoins += format(" AND a.\"%s\" = %c.\"%s\"", ffrom, alias_letter, fto);
+					}
+					last_fk_id = fk_id;
+				}
+				stmt.finalize();
+
+				fields_csv = "a.\"" + fields.concat("\",\n\ta.\"") + "\"";
+				sql = format("--CREATE VIEW \"%s_list_view\" AS\nSELECT\n\t%s\nFROM \"%s\" AS a\nLIMIT %d", 
+					tbl, fields_csv, tbl, iMaxRows->value().tointeger());
+				sql += myjoins;
+			}
+			else if(sql == "insert") sql = format("INSERT INTO \"%s\"(%s)\nVALUES(%s)", tbl, fields_csv, fields_csv);
 			else if(sql == "update") {
-				str_fields = fields.concat("=?, ");
-				sql = format("update %s set %s=?\nwhere id=?", tbl, str_fields);
+				fields_csv = "\"" + fields.concat("\"=?, \"") + "\"";
+				sql = format("UPDATE \"%s\" SET %s=?\nWHERE \"id\"=?", tbl, fields_csv);
+			}
+			else if(sql == "delete") sql = format("DELETE FROM \"%s\" WHERE \"id\"=?", tbl);
+			else if(sql == "create index") sql = format("CREATE INDEX \"%s_idx\" ON \"%s\"(\"field\" COLLATE NOCASE)", tbl, tbl);
+			else if(sql == "create trigger") sql = format("CREATE TRIGGER \"%s_trigger\"\nBEFORE/AFTER/INSTEAD OF INSERT, UPDATE, DELETE OF col_name ON \"%s\"\nFOR EACH ROW WHEN expr\nBEGIN\nEND;", tbl, tbl);
+			else if(sql == "drop table")
+			{
+				local table_type = db.exec_get_one("SELECT \"type\" FROM sqlite_master WHERE name='" + tbl + "'");
+				sql = format("DROP %s \"%s\"", table_type, tbl);
+			}
+			else if(sql == "dump table")
+			{
+				local result = blob(0, 8192);
+				local str_schema = getSchemaFor(tbl);
+				str_schema = str_schema.gsub("\n%s+", "\n\t");
+				result.write("BEGIN;\n\n", str_schema, ";");
+				getIndexesAndTriggersFor(tbl, result);
+				fields_csv = fields_csv.gsub(", ", ",\n\t");
+				result.write(format("\n\nINSERT INTO \"%s\" (\n\t%s\n\t) VALUES", tbl, fields_csv));
+
+				local result_size = result.len();
+				local stmt = db.prepare(format("SELECT * FROM \"%s\"", tbl));
+				local col_count = stmt.col_count();
+				
+				local SQLITE_INTEGER = stmt.SQLITE_INTEGER;
+				local SQLITE_FLOAT = stmt.SQLITE_FLOAT;
+				local SQLITE_NULL = stmt.SQLITE_NULL;
+				local SQLITE_TEXT = stmt.SQLITE_TEXT;
+				local SQLITE_BLOB = stmt.SQLITE_BLOB;
+				
+				while(stmt.next_row())
+				{
+					result.write("\n(");
+					for(local i=0; i < col_count; ++i)
+					{
+						local value = stmt.col(i);
+						if(i) result.write(",");
+						
+						local ctype = stmt.col_type(i);
+
+						if(ctype == SQLITE_INTEGER  || ctype == SQLITE_FLOAT)
+							result.write(value.tostring());
+							
+						else if(ctype == SQLITE_NULL) result.write("NULL");
+						else if(ctype == SQLITE_TEXT) result.write("'", value.gsub("'", "''") ,"'");
+						else if(ctype == SQLITE_BLOB) result.write(format("%q", value));
+						else result.write("??");
+					}
+					result.write("),");
+				}
+				stmt.finalize();
+				
+				if(result_size < result.len())
+				{
+					result.resize(result.len()-1); //delete last comma
+					result.write(";");
+				}
+				
+				result.write("\n\nCOMMIT;");
+				sql = result.tostring();
+			}
+			else if(sql == "references") sql = tbl;
+			else if(sql == "schema update") {
+				sql = genSchemaUpgrade(true);
+			}
+			else if(sql == "schema update norefs") {
+				sql = genSchemaUpgrade(false);
+			}
+			else if(sql == "sqlite_master update") {
+				local result = blob(0, 8192);
+				local schema_version = getSchemaVersion();
+				result.write("BEGIN;\n--PRAGMA schema_version; --> ", schema_version.tostring(), "\n\n");
+				result.write("PRAGMA writable_schema=ON;\n\n");
+				local str_schema = getSchemaFor(tbl);
+				str_schema = str_schema.gsub("\n%s+", "\n\t");
+				str_schema = str_schema.gsub("'", "''");
+				
+				result.write("UPDATE sqlite_master\nSET sql='", str_schema, "'\nWHERE type='table' AND name='", tbl, "';\n\n"); 
+				
+				local stmt = db.prepare(getIndexesSqlFor(tbl));
+				while(stmt.next_row())
+				{
+					local str = stmt.col(1);
+					if(::type(str) == "string") result.write("\n\n", str, ";");
+				}
+				stmt.finalize();
+
+				stmt = db.prepare(getTriggersSqlFor(tbl));
+				while(stmt.next_row())
+				{
+					local str = stmt.col(1);
+					if(::type(str) == "string") result.write("\n\n", str, ";");
+				}
+				stmt.finalize();
+				
+				result.write("\n\nDROP VIEW \"view_name\";\n\n");
+				result.write(getReferencesOnDBSchema(db, tbl));
+				result.write("\n\nCREATE VIEW  \"view_name\"  AS \"db_table_name\";");
+				result.write("\n\nPRAGMA schema_version=", (schema_version.tointeger() + 1).tostring(), 
+					";\n\nPRAGMA writable_schema=OFF;\n\nPRAGMA integrit_check;\n\nCOMMIT;");
+				sql = result.tostring();
 			}
-			else if(sql == "delete") sql = format("delete from %s where id=?", tbl);
 			else return;
 			edit_queries->value(sql);
 		}
 	}
+	
+	function refreshTabView(tbl)
+	{
+		local tab = tabView->value();
+		local sql = false;
+		local the_grid = false;
+		if(tab == viewFields)
+		{
+			sql = format("PRAGMA table_info(\"%s\");", tbl);
+			the_grid = grid_fields;
+		}
+		if(tab == viewIndexes)
+		{
+			sql = getIndexesSqlFor(tbl);
+			the_grid = gridIndexes;
+		}
+		else if(tab == viewTriggers)
+		{
+			sql = getTriggersSqlFor(tbl);
+			the_grid = gridTriggers;
+		}
+		else if(tab == groupSchema)
+		{
+			local str = getSchemaFor(tbl);
+			edit_schema->value(str);
+		}
+
+		if(sql && the_grid)
+		{
+			get_records_by_sql(the_grid, sql, true);
+		}
+	}
+  
+	function tabView_cb(sender, udata){
+		this = sender->window();
+		//print(tab->label());
+		local tbl = grid_tables.get_value(grid_tables.row(), 1);
+		if(tbl)
+		{
+			refreshTabView(tbl);
+		}
+	}
   
 	function set_label_dbf(dbf){
 		db_file_name = dbf;
@@ -340,6 +983,23 @@ class Sqlite3CC extends Sqlite3cc_Window {
 		if (dbf) label_title += " - " + dbf;
 		label(label_title);
 	}
+	
+	function queryAsArrayOfArrays(sql)
+	{
+		local result = [];
+		local qry = db.exec_query(sql);
+		local col_count = qry.col_count();
+		local header = [];
+		for(local i=0; i < col_count; ++i){
+			header.append(qry.col_name(i));
+		}
+		result.append(header);
+		while(qry.next_row()){
+			result.append(qry.row_as_array());
+		}
+		qry.close();
+		return result;
+	}
 
 	function get_records_by_sql(grid, sql , named=false){
 		local cursor_wait = fl_cursor_wait();
@@ -350,8 +1010,27 @@ class Sqlite3CC extends Sqlite3cc_Window {
 	}
 
 	function get_tables(){
-		local sql = "select rowid as 'rowid|ID|0', name as 'name|Name|-1', type as 'type|Type|4' from sqlite_master where (type='table' OR type='view') order by name";
+		local sql = "SELECT rowid AS 'rowid|ID|0', name AS 'name|Name|-1', type as 'type|Type|4' FROM sqlite_master WHERE (type='table' OR type='view') ORDER BY name";
 		get_records_by_sql(grid_tables, sql, true);
+		_the_schema_version = getSchemaVersion();
+		_my_tables_data = grid_tables->_data;
+	}
+	
+	function openDB(the_db_file_name)
+	{
+		if (the_db_file_name) {
+			//print(dbf);
+			if (db) db.close();
+			attached_databases = {};
+			set_label_dbf(the_db_file_name);
+			// SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_SUBLATIN_NA_LIKE
+			db = SQLite3(the_db_file_name);
+			//db.exec_dml("PRAGMA mmap_size=268435456;");
+			//db.trace(function(udata, sql){print(udata, ":", sql);}, "SQL");
+			//db.create_function("multiply3",3, multiply3); //SQLITE_DETERMINISTIC
+			get_tables();
+			Fl.preferences_set("last_db_file_name", the_db_file_name);
+		}
 	}
 
 	function menuBar_cb(sender, udata){
@@ -359,36 +1038,26 @@ class Sqlite3CC extends Sqlite3cc_Window {
 		//fl_alert(format("%d = %s", sender.value(), sender.text()));
 		//print(sender, udata, sender.value(), menu_file_exit);
 		local choice = sender.value();
+		local path = db_file_name ? db_file_name.gsub("/[^/]+$", "") : null;
 		if(choice == menu_file_new) {
-			local dbf = fl_file_chooser(_tr("Select a database"), "*.db", null);
-			if (dbf) {
-				//print(dbf);
-				if (db) db.close();
-				attached_databases = {};
-				set_label_dbf(dbf);
-				db = SQLite3(dbf);
-			}
+			local dbf = fl_file_chooser(_tr("Select a database"), "*.db", path);
+			openDB(dbf);
 		}
 		else if(choice == menu_file_open) {
-			local dbf = fl_file_chooser(_tr("Select a database"), "*.db", null);
-			if (dbf){
-				//print(dbf);
-				if (db) db.close();
-				attached_databases = {};
-				set_label_dbf(dbf);
-				// SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_SUBLATIN_NA_LIKE
-				db = SQLite3(dbf);
-				get_tables();
-			}
+			local dbf = fl_file_chooser(_tr("Select a database"), "*.db", path);
+			openDB(dbf);
+		}
+		else if(choice == menu_file_reopen) {
+			if(db) openDB(db_file_name);
 		}
 		else if(choice == menu_file_attach) {
-			local dbf = fl_file_chooser(_tr("Select a database"), "*.db", null);
+			local dbf = fl_file_chooser(_tr("Select a database"), "*.db", path);
 			if (dbf){
 				//print(dbf)
 				local dbname = fl_input(_tr("Attach database with name ?"), "adb");
 				if (dbname && !attached_databases.get(dbname, false)){
 					attached_databases[dbname] <- true;
-					local sql = format("attach database '%s' as %s;", dbf, dbname);
+					local sql = format("ATTACH DATABASE '%s' as %s;", dbf, dbname);
 					db.exec_dml(sql);
 					get_tables();
 				}
@@ -417,6 +1086,7 @@ class Sqlite3CC extends Sqlite3cc_Window {
 	}
 }
 
+fl_preferences(Fl.FL_PREFERENCES_USER, "dadbiz", "sqlite3-cc");
 Fl.scheme("gtk+");
 Fl.visual(FL_RGB);
 //allow arrow keys navigation
@@ -427,4 +1097,6 @@ local win = new Sqlite3CC();
 win->resizable(win);
 win->show_main();
 
-Fl.run();
+Fl.run();
+
+Fl.preferences_flush();