Graal Pastebin
New PastePasted on July 23, 2011.
View the raw file
/* SQL Explorer v2.2 by Chris Vimes Latest version can always be found at http://code.graalcenter.org/sqlexplorer/ Watch for updates at http://forums.graalonline.com/forums/showthread.php?t=134256319 @@@@@@@@@ UPGRADE WARNING! @@@@@@@@@ @ Rights control has been REMOVED in v2.2 @ so make sure not to give this to anybody @ you don't trust @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Stuff to improve: - Table Viewing Allow multiple selections when removing rows - Table Manipulation Add automatic column removing (through backup/recreate table method) - Backup Add some form of import/export for tables and their data Thanks to: Jer (fowlplay4) - SQL Worksheet - http://forums.graalonline.com/forums/showthread.php?p=1483720 - Number Formatter - http://forums.graalonline.com/forums/showthread.php?p=1643646 ...among others Image credits available at: - http://wiki.graal.net/index.php/File:Database.png - http://wiki.graal.net/index.php/File:DatabaseSmall.png - http://wiki.graal.net/index.php/File:DatabaseIcon.png */ // update this to match your server until a way is added/found to get the list // dynamically function getDatabaseList() { // {name, filename} return { {"default", "main"} }; } function onCreated() { // basic options this.rowsPerRequest = 100; // maximum number of rows per request (e.g. will paginate after x number of rows) ->>>> anywhere near 500, and it starts to lag // right control this.requireNC = true; // everything below here can be left alone this.allowedFuncs = {"getDatabases", "getTable", "getNewPage", "doCreateTable", "doDropTable", "doRenameTable", "doDuplicateTable", "doDropIndex", "doAddColumn", "getCreateIndexColumns", "doCreateIndex", "doGetTableSchema", "doGetIndexSchema", "getRowContentsForModify", "doDuplicateRow", "doDeleteRows", "getRowContentsForInsert", "doInsertRow", "doModifyRow", "doExecuteQuery", "getDatabaseInfo", "updateSyncSetting", "defragDatabase"}; } function onActionServerSide(cmd, func, par) { temp.cname = player.communityName; if (temp.cname == null) { temp.cname = player.account; } if (serveroptions.staff.tokenize(",").index(temp.cname) <= (- 1)) { printf("Hacker (?): %s (%s) tried to use SQL Explorer but is not in server options as staff", player.account, temp.cname, func); } if (this.requireNC) { if (! player.hasRightFlag("NPC-Control")) { printf("Hacker (?): %s (%s) tried to use SQL Explorer but doesn't have NC", player.account, temp.cname, func); } } if (cmd in {"get", "tell"} && this.allowedFuncs.index(@ func) <= (- 1)) { return printf("Hacker (?): %s (%s) tried to send unrequestable function (%s) to the SQL Explorer", player.account, temp.cname, func); } switch (cmd) { case "get": temp.result = this.(@ func)(par); if (result == "NOSEND") { return; } triggerclient("gui", name, "return", func, result); break; case "tell": this.(@ func)(par); break; } } // serverside functions function getDatabases() { temp.databases = getDatabaseList(); temp.dbs = null; for (temp.db : databases) { dbs.add({db[0], getTables(db[0])}); } return {dbs, this.hasDatabaseRead()}; } function getDatabaseInfo(temp.dbName) { temp.fileName = null; for (temp.database : this.getDatabaseList()) { if (temp.database[0] == temp.dbName) { temp.fileName = temp.database[1] @ ".db"; } } temp.dbSize = filesize("databases/" @ temp.fileName); temp.tableCount = req(temp.dbName, "SELECT count(*) AS tablecount FROM sqlite_master WHERE type = 'table'", true)[0].tablecount; temp.synchronous = req(temp.dbName, "PRAGMA synchronous", true)[0][0]; return {temp.dbName, temp.fileName, temp.dbSize, temp.tableCount, temp.synchronous}; } function getTables(db) { temp.tables = null; temp.id = new TStaticVar(); for (temp.idx : req(db, "SELECT name, tbl_name, sql FROM 'sqlite_master' WHERE type = 'index' AND sql NOT NULL ORDER BY name", true)) { // from the schema, get the column it's on temp.sql = idx[2]; temp.tokens = sql.tokenize("("); temp.loc = tokens[tokens.size() - 1]; loc = loc.substring(0, loc.pos(")")); id.(@ idx[1]).add({idx[0], loc}); } for (temp.table : req(db, "SELECT name FROM 'sqlite_master' WHERE type = 'table' ORDER BY name", true)) { tables.add({table[0], id.(@ table[0])}); } temp.id.destroy(); return tables; } function getTable(data) { temp.db = data[0]; temp.table = data[1]; // first, get information about the columns temp.columns = {"rowid"}; for (temp.column : req(db, "PRAGMA table_info('" @ table @ "')", true)) { columns.add(column[1]); } // now get the rows temp.rows = req(db, "SELECT rowid, * FROM '" @ table @ "' LIMIT " @ this.rowsPerRequest, true); temp.numRows = req(db, "SELECT count(*) FROM '" @ table @ "'", true)[0][0]; return {{db, table}, columns, rows, numRows}; } function updateSyncSetting(temp.data) { temp.dbName = temp.data[0]; temp.setting = temp.data[1]; req(temp.dbName, "PRAGMA synchronous = " @ temp.setting, false); return temp.setting; } function defragDatabase(temp.dbName) { sqliteDefragment(temp.dbName); this.onActionServerSide("get", "getDatabaseInfo", temp.dbName); } function getNewPage(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.start = data[1]; temp.dir = data[2]; temp.sortMode = data[3]; temp.filter = data[4]; start += dir * this.rowsPerRequest; start = max(0, start); temp.condition = ""; if (filter.size() > 0) { condition = " WHERE " @ escapestring2(filter[0]) @ " "; temp.add = ""; switch (filter[1]) { case "contains": add = "LIKE '%" @ escapeLike(escapestring2(filter[2])) @ "%' ESCAPE '`'"; break; case "LIKE": add = "LIKE '" @ escapestring2(filter[2]) @ "'"; break; case "=": case "!=": case "<": case "<=": case ">": case ">=": add = filter[1] @ " " @ formatForInput(escapestring2(filter[2])); break; } condition @= add; } temp.rows = req(db, "SELECT rowid, * FROM '" @ table @ "'" @ condition @ " ORDER BY " @ sortMode[0] @ " COLLATE NOCASE" @(sortMode[1] ? " DESC" : "") @ " LIMIT " @ start @ ", " @ this.rowsPerRequest, true); // LIMIT start, number temp.numRows = req(db, "SELECT count(*) FROM '" @ table @ "'" @ condition, true)[0][0]; return {{db, table}, start, rows, numRows}; } function escapeLike(input) { input = replaceText(input, "%", "`%"); input = replaceText(input, "_", "`_"); return input; } function formatForInput(input) { if (input.type() in {1, 2}) { return "'" @ input @ "'"; } return input; } function replacetext(txt,a,b) { // credits to dusty if (txt.pos(a)<0) return txt; temp.txtpos = txt.positions(a); temp.newtxt = txt.substring(0,txtpos[0]); for (temp.i=0;i<txtpos.size();i++) { newtxt @= b; newtxt @= txt.substring(txtpos[i]+a.length(),txt.substring(txtpos[i]+a.length()).pos(a)); } return newtxt; } function doCreateTable(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.columns = data[1]; temp.sql = "CREATE TABLE '" @ table @ "' ("; // name, type, default, default is null, unique, auto_inc, not null for (temp.col : columns) { sql @= col[0] @ " " @ col[1].upper() @ " DEFAULT "; if (col[3]) { sql @= "NULL"; } else { if (col[1] in {"Real", "Integer"}) { sql @= (0 + col[2]); } else { sql @= "'" @ escapestring2(col[2]) @ "'"; } } if (col[4]) { sql @= " UNIQUE"; } if (col[5]) { sql @= " PRIMARY KEY"; } if (col[6] && ! col[3]) { sql @= " NOT NULL"; } sql @= ", "; } sql = sql.substring(0, sql.length() - 2); sql @= ")"; req(db, sql); //triggerClient("gui", this.name, "return", "getDatabases", getDatabases()); refresh(); } function doDropTable(data) { temp.db = data[0]; temp.table = data[1]; req(db, "DROP TABLE '" @ table @ "'"); refresh(); } function doRenameTable(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.newName = data[1]; req(db, "ALTER TABLE '" @ table @ "' RENAME TO '" @ newName @ "'"); refresh(); } function doDuplicateTable(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.newName = data[1]; req(db, "CREATE TABLE '" @ newName @ "' AS SELECT * FROM '" @ table @ "'"); refresh(); } function doDropIndex(data) { temp.db = data[0]; temp.idx = data[1]; temp.tbl_name = req(db, "SELECT tbl_name FROM 'sqlite_master' WHERE type = 'index' AND name = '" @ idx @ "'", true)[0][0]; req(db, "DROP INDEX '" @ idx @ "'"); refresh(); } function doAddColumn(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.col = data[1]; temp.sql = "ALTER TABLE '" @ table @ "' ADD COLUMN " @ col[0] @ " " @ col[1].upper @ " DEFAULT "; if (col[3]) { sql @= "NULL"; } else { if (col[1] in {"Real", "Integer"}) { sql @= col[2]; } else { sql @= "'" @ escapestring2(col[2]) @ "'"; } } if (col[6] && ! col[3]) { sql @= " NOT NULL"; } req(db, sql); msg("Column added to '" @ db @ "." @ table @ "' successfully!"); } function getCreateIndexColumns(data) { temp.db = data[0]; temp.table = data[1]; temp.columns = null; for (temp.col : req(db, "PRAGMA table_info('" @ table @ "')", true)) { columns.add(col[1]); } return {{db, table}, columns}; } function doCreateIndex(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.column = data[1]; temp.idx = data[2]; req(db, "CREATE INDEX '" @ idx @ "' ON '" @ table @ "' (" @ column @ ")"); refresh(); } function doGetTableSchema(data) { temp.db = data[0]; temp.table = data[1]; msg2("Table schema for '" @ db @ "." @ table @ "':", req(db, "SELECT sql FROM 'sqlite_master' WHERE type = 'table' AND name = '" @ table @ "'", true)[0][0]); } function doGetIndexSchema(data) { temp.db = data[0]; temp.idx = data[1]; temp.table = req(db, "SELECT tbl_name FROM 'sqlite_master' WHERE type = 'index' AND name = '" @ idx @ "'", true)[0][0]; msg2("Index schema for '" @ db @ "." @ idx @ "':", req(db, "SELECT sql FROM 'sqlite_master' WHERE type = 'index' AND name = '" @ idx @ "'", true)[0][0]); } function getRowContentsForModify(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.rowid = data[1]; temp.start = data[2]; temp.columns = null; for (temp.col : req(db, "PRAGMA table_info('" @ table @ "')", true)) { columns.add(col[1]); } temp.row = req(db, "SELECT * FROM '" @ table @ "' WHERE rowid = " @ rowid, true)[0]; return {{db, table}, rowid, columns, row, start}; } function doDuplicateRow(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.rowid = data[1]; temp.start = data[2]; temp.sort = data[3]; temp.filter = data[4]; req(db, "INSERT INTO '" @ table @ "' SELECT * FROM '" @ table @ "' WHERE rowid = " @ rowid); onActionServerSide("get", "getNewPage", {{db, table}, start, 0, sort, filter}); } function doDeleteRows(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.rowids = data[1]; temp.start = data[2]; temp.sort = data[3]; temp.filter = data[4]; for (temp.rowid : temp.rowids) { req(db, "DELETE FROM '" @ table @ "' WHERE rowid = " @ rowid); } onActionServerSide("get", "getNewPage", {{db, table}, start, 0, sort, filter}); } function getRowContentsForInsert(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.start = data[1]; temp.columns = null; for (temp.col : req(db, "PRAGMA table_info('" @ table @ "')", true)) { columns.add(col[1]); } return {{db, table}, columns, start}; } function doInsertRow(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.columns = data[1]; temp.start = data[2]; temp.sort = data[3]; temp.filter = data[4]; temp.sql = "INSERT INTO '" @ table @ "' VALUES ("; for (temp.col : columns) { if (col[0]) { sql @= "'" @ col[1] @ "', "; } else { sql @= "NULL, "; } } sql = sql.substring(0, sql.length() - 2) @ ")"; req(db, sql); onActionServerSide("get", "getNewPage", {{db, table}, start, 0, sort, filter}); } function doModifyRow(data) { temp.db = data[0][0]; temp.table = data[0][1]; temp.rowid = data[1]; temp.columns = data[2]; temp.start = data[3]; temp.sort = data[4]; temp.filter = data[5]; temp.rcolumns = null; for (temp.col : req(db, "PRAGMA table_info('" @ table @ "')", true)) { rcolumns.add(col[1]); } temp.sql = "UPDATE '" @ table @ "' SET "; temp.c = 0; for (temp.col : columns) { if (col[0]) { sql @= rcolumns[c] @ " = '" @ col[1] @ "', "; } else { sql @= rcolumns[c] @ " = NULL, "; } c ++; } sql = sql.substring(0, sql.length() - 2) @ " WHERE rowid = " @ rowid; req(db, sql); onActionServerSide("get", "getNewPage", {{db, table}, start, 0, sort, filter}); } function doExecuteQuery(data) { temp.db = data[0]; temp.query = data[1]; temp.tokens = query.tokenize(";"); for (temp.token : tokens) { this.trigger("performQuery", db, token); } } function onPerformQuery(db, query) { if (query.lower().starts("echo")) { return sqlEcho(query.substring(5).trim()); } temp.results = requestsql2(db, query, true); if (results.error != null) { // error! return sqlEcho("Error: " @ results.error); } if (results.rows.size() > 0) { // rows returned temp.rows = null; temp.columns = results.rows[0].getDynamicVarNames(); for (temp.row : results.rows) { temp.data = null; for (temp.column : columns) { data.add(row.(@ column)); } rows.add(data); } triggerclient("gui", name, "execute", "results", {columns, rows}); } else if (results.affectedrows > 0) { sqlEcho("Query affected " @ results.affectedrows @ " rows."); } else { sqlEcho(query.tokenize()[0].upper() @ " query completed successfully"); // this needs to be improved - things like "ALTER TABLE" will appear as "ALTER" } } function sqlEcho(msg) { triggerclient("gui", name, "execute", "echo", msg); } // SQL functions public function req(db, request, wait) { temp.req = requestsql2(db, request, wait); if (req.error != "") { errorSql(req.error, request); if (! wait) { return req.error; } } if (! wait) { return; } if (! req.completed) { waitfor(req, "onReceiveData", 60); } return req.rows; } function errorSql(error, query) { echo("SQL Explorer Error:" SPC error); echo(" Query:" SPC query); msg2("SQL Explorer has encountered a SQL error. This may be the fault of internal coding, or of poor user input. If you believe this is a bug, please report it.", "<b>Query:</b> " @ query @ "\\n <b>Error:</b> " @ error); } // Message Functions function msg(msg) { triggerclient("gui", name, "msg", msg); } function msg2(msg, msg2) { triggerclient("gui", name, "msg2", msg, msg2); } // Misc functions function hasDatabaseRead() { temp.pl = new TServerPlayer("(npcserver)"); temp.has = temp.pl.hasRight("r", "databases/main.db"); temp.pl.destroy(); return temp.has; } function refresh() { this.onActionServerSide("get", "getDatabases"); } //#CLIENTSIDE // basic variables (can be left alone) const VERSION = "v2.2"; // version const SIZE_INIT_W = 500; // initial width const SIZE_INIT_H = 400; // initial height const MIN_W = 350; const MIN_H = 250; const TOGGLE_KEY = "n"; // key to toggle open/close function onCreated() { // some GUI stuff SQLContextScrollProfile = new GuiBlueScrollProfile(); SQLContextScrollProfile.border = 1; if (isObject("SQL_Window")) { SQL_Window.destroy(); // updating the script causes it to become unresponsive } // temp: //this.showExplorer(); } function onKeyPressed(code, key) { if (key == TOGGLE_KEY) { // toggle explorer if (isObject("SQL_Window")) { SQL_Window.visible = ! SQL_Window.visible; } else { showExplorer(); } } } // Server -> Client data function getCommand(func, data) { switch (func) { case "getDatabases": SQL_Execute_Database.active = true; SQL_Execute_Database.clearRows(); for (temp.db : data[0]) { SQL_Execute_Database.addRow(0, db[0]); } if (! data[1]) { SQL_Tabs.rows[2].displayMessage = "You need to give the NPC-server the folder right \"r databases/" @ "*.db\" for this part of SQL Explorer to fully function."; } SQL_Execute_Database.setSelectedRow(SQL_Execute_Database.findText("default")); with (SQL_Data_DBs_Tree) { clearNodes(); active = true; with (SQL_Databases_List) { this.clearRows(); this.profile.modal = true; this.active = true; this.setIconSize(40, 42); } for (temp.db : data[0]) { with (addNode(db[0])) { for (temp.table : db[1]) { with (addNode(table[0])) { this.database = db[0]; for (temp.idx : table[1]) { with (addNode(idx[0] @ " (" @ idx[1] @ ")")) { image = selectedimage = 2; this.indexName = idx[0]; this.columns = idx[1]; } } this.expanded = false; } } this.expanded = true; } temp.row = SQL_Databases_List.addRow(0, temp.db[0]); temp.row.dbName = temp.db[0]; temp.row.icon.drawimage(5, 5, "sqlexplorer_database-small.png"); } } SQL_Data_DBs_Refresh.active = true; break; case "getDatabaseInfo": temp.dbName = temp.data[0]; temp.fileName = temp.data[1]; temp.fileSize = temp.data[2]; temp.tableCount = temp.data[3]; temp.sync = temp.data[4]; temp.syncOptions = {"Off", "Normal", "Full"}; SQL_Databases_Loading.visible = false; SQL_Databases_DatabaseInfo.visible = true; SQL_Databases_List.active = true; SQL_Databases_DatabaseLabel.text = "<center><b>" @ temp.dbName; SQL_Databases_DatabaseInfo_0.text = "<center><b>Database File:</b> " @ temp.fileName; SQL_Databases_DatabaseInfo_1.text = "<center><b>Database Size:</b> " @ this.formatSize(temp.fileSize); SQL_Databases_DatabaseInfo_2.text = "<center><b>Table Count:</b> " @ temp.tableCount; SQL_Databases_DatabaseInfo_3.text = "<center><b>Synchronous:</b>";// " @ temp.syncOptions[temp.sync]; SQL_Databases_SyncList.selectedSync = temp.sync; SQL_Databases_SyncList.setSelectedRow(temp.sync); break; case "getTable": temp.db = data[0][0]; temp.table = data[0][1]; temp.columns = data[1]; temp.tColumns = columns; temp.tRows = data[2]; temp.maxRows = data[3]; SQL_Data_DBs_Tree.getNodeByPath(db @ "%" @ table, "%").isWaiting = false; // build up width for the columns temp.columnDims = {0}; for (c = 0; c < columns.size(); c ++) { temp.dim = GuiBlueMLTextProfile.getTextWidth(columns[c]); temp.m = 0; for (temp.row : tRows) { temp.s = GuiBlueTextListProfile.getTextWidth(row[c]); if (dim < s) { dim = s; } m ++; if (m >= 50) { break; // next column (only sample 50 rows) } m ++; } columnDims.add(columnDims[columnDims.size() - 1] + dim + 12); } // draw the tab with (addDataTab(db @ "." @ table, table)) { temp.par = this; vScrollBar = "alwaysOff"; hScrollBar = "alwaysOff"; new GuiScrollCtrl("SQL_Data_Table_" @ table @ "_Container") { profile = GuiBlueScrollProfile; width = par.width; height = par.height - 67; x = (- 2); y = (- 2); vertSizing = "height"; horizSizing = "width"; vScrollBar = "alwaysOn"; hScrollBar = "dynamic"; thiso.catchEvent(this, "onResize", "onTableResized"); thiso.catchEvent(this, "onScrolled", "onContainerScrolled"); this.tbl = table; this.database = db; par.database = db; par.con = this; temp.con = this; new GuiControl("SQL_Data_Table_" @ table @ "_Columns") { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = "114 148 182"; x = (- 2); y = (- 2); width = 24; height = 28; con.columns = this; this.tbl = table; thiso.catchEvent(this, "onMouseDown", "onColumnClicked"); thiso.catchEvent(this, "onRightMouseDown", "onTableRightClicked"); temp.c = 0; this.database = db; for (temp.colD : columnDims) { temp.column = tColumns[c]; new GuiMLTextCtrl("SQL_Data_Table_" @ table @ "_Columns_DividerText_" @ c) { profile = GuiBlueMLTextProfile; useownprofile = true; profile.fontColor = "0 0 0"; profile.modal = false; x = colD + 6; y = 7; width = profile.getTextWidth("<b>" @ column @ "</b>"); text = column == null ? "" : (column); this.columnNum = c; this.realText = text; if (c == 0) { // sorted by con.columns.sortColumn = this; text = "<b> " @ text @ "</b>"; } con.columns.dividerTexts.add(this); con.dividerTexts.add(this); } new GuiControl("SQL_Data_Table_" @ table @ "_Columns_Divider_" @ c) { useownprofile = true; profile.border = 1; x = colD; y = 0; minExtent = "0 0"; width = 1; height = 28; this.myMin = GuiBlueMLTextProfile.getTextWidth(tColumns[c - 1] == null ? "" : tColumns[c - 1]) + 12; this.columnNum = c; thiso.catchEvent(this, "onMouseEnter", "onMouseOverDivider"); thiso.catchEvent(this, "onMouseLeave", "onMouseLeavesDivider"); thiso.catchEvent(this, "onMouseDown", "onMouseDragsDivider"); thiso.catchEvent(this, "onMouseUp", "onMouseUpDivider"); con.dividers.add(this); } c ++; } } new GuiScrollCtrl("SQL_Data_Table_" @ table @ "_TableContainer") { useownprofile = true; profile.opaque = false; profile.bitmap = ""; x = 0; y = 0; width = 100; height = 100; con.tc = this; vScrollBar = "alwaysOff"; hScrollBar = "alwaysOff"; temp.c = 0; for (temp.cDim : columnDims) { if (c == 0) { c ++; continue; } new GuiControl("SQL_Data_Table_" @ table @ "_Divider_" @ c) { useownprofile = true; profile.border = 1; x = cDim - 3; y = 25; minExtent = "0 0"; width = 1; height = 100; con.dividers2.add(this); visible = tRows.size() > 0; } c ++; } new GuiTextListCtrl("SQL_Data_Table_" @ table) { profile = GuiBlueTextListProfile; x = 0; y = 25; fitparentwidth = false; this.sortCMode = {"rowid", 0}; // column, descending? this.colDim = columnDims; this.colNames = data[1]; columns = columnDims; clipcolumntext = true; allowMultipleSelections = true; this.tbl = table; this.database = db; temp.max = 0; for (temp.row : tRows) { temp.line = row[0]; for (temp.i = 1; i < row.size(); i ++) { line @= "\t" @ row[i]; max ++; if (max >= 9999) { max = 0; sleep(0.05); // avoid the max loop limit! } } temp.r = addRow(0, line); r.rowid = row[0]; } con.table = this; thiso.catchEvent(this, "onMouseWheelUp", "onScrollUp"); thiso.catchEvent(this, "onMouseWheelDown", "onScrollDown"); thiso.catchEvent(this, "onOpenMenu", "onTableRightClicked"); } } } new GuiControl("SQL_Data_Table_" @ table @ "_Navigator") { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = "255 255 255 70"; width = par.width; height = 35; x = (- 2); y = par.height - height - 2; horizSizing = "width"; vertSizing = "top"; new GuiButtonCtrl("SQL_Data_Table_" @ table @ "_PageLeft") { profile = GuiBlueButtonProfile; width = 30; height = 25; x = 5; y = 5; text = "<"; active = false; thiso.catchEvent(this, "onAction", "onPageLeft"); con.lB = this; } new GuiButtonCtrl("SQL_Data_Table_" @ table @ "_PageRight") { profile = GuiBlueButtonProfile; width = 30; height = 25; x = par.width - width - 5; y = 5; text = ">"; active = tRows.size() < maxRows; horizSizing = "left"; thiso.catchEvent(this, "onAction", "onPageRight"); con.rB = this; } new GuiMLTextCtrl("SQL_Data_Table_" @ table @ "_RowCount") { profile = GuiBlueMLTextProfile; useownprofile = true; profile.modal = false; profile.fontColor = "0 0 0"; x = 0; y = 10; width = par.width; text = "<center>Viewing rows 1-" @ thiso.separate(tRows.size()) @ " of " @ thiso.separate(maxRows) @ "</center>"; horizSizing = "width"; con.rowCount = this; } } new GuiControl("SQL_Data_Table_" @ table @ "_Filter") { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = "255 255 255 70"; width = par.width; height = 33; x = (- 2); y = par.height - height - (@ "SQL_Data_Table_" @ table @ "_Navigator").height - 1; horizSizing = "width"; vertSizing = "top"; temp.filter = this; con.filterO = this; new GuiPopUpMenuCtrl("SQL_Data_Table_" @ table @ "_FilterColumns") { profile = GuiBluePopUpMenuProfile; scrollprofile = GuiBlueScrollProfile; textprofile = GuiBlueTextListProfile; x = 5; y = 5; width = 125; height = 23; clearRows(); for (temp.c : tColumns) { addRow(0, c); } setSelectedRow(1); filter.fColumns = this; } new GuiPopUpMenuCtrl("SQL_Data_Table_" @ table @ "_FilterCompare") { profile = GuiBluePopUpMenuProfile; scrollprofile = GuiBlueScrollProfile; textprofile = GuiBlueTextListProfile; useownprofile = true; profile.align = "center"; x = 135; y = 5; width = 75; height = 23; temp.compares = {"contains", "LIKE", "=", "<", ">", "<=", ">=", "!="}; clearRows(); for (temp.c : compares) { addRow(0, c); } setSelectedRow(0); filter.fCompare = this; } new GuiButtonCtrl("SQL_Data_Table_" @ table @ "_X") { profile = GuiBlueButtonProfile; width = 30; height = 23; x = filter.width - width - 5; y = 5; text = "x"; active = false; horizSizing = "left"; filter.fX = this; thiso.catchEvent(this, "onAction", "onFilterXButtonClicked"); } new GuiButtonCtrl("SQL_Data_Table_" @ table @ "_Go") { profile = GuiBlueButtonProfile; width = 60; height = 23; x = filter.width - width - (@ "SQL_Data_Table_" @ table @ "_X").width - 10; y = 5; text = "Filter"; horizSizing = "left"; thiso.catchEvent(this, "onAction", "onFilterButtonClicked"); filter.fGo = this; } new GuiTextEditCtrl("SQL_Data_Table_" @ table @ "_Value") { profile = GuiBlueTextEditProfile; x = 215; y = 5; width = filter.width - (filter.width - (@ "SQL_Data_Table_" @ table @ "_Go").x) - x - 5; height = 23; text = ""; horizSizing = "width"; filter.fValue = this; } } } ("SQL_Data_Table_" @ table).baseWidth = ("SQL_Data_Table_" @ table).width; ("SQL_Data_Table_" @ table).pushToBack(); for (temp.div : ("SQL_Data_Table_" @ table @ "_Container").dividers2) { div.height = ("SQL_Data_Table_" @ table).height; } ("SQL_Data_Table_" @ table @ "_TableContainer").width = max(("SQL_Data_Table_" @ table).width, ("SQL_Data_Table_" @ table @ "_Container").width - 24); ("SQL_Data_Table_" @ table @ "_TableContainer").height = ("SQL_Data_Table_" @ table).height + 27; //("SQL_Data_Table_" @ table @ "_TableContainer").minExtent = ("SQL_Data_Table_" @ table).width @ " " @ ("SQL_Data_Table_" @ table @ "_TableContainer").height; ("SQL_Data_Table_" @ table).fitParentWidth = true; ("SQL_Data_Table_" @ table).width = max(("SQL_Data_Table_" @ table).baseWidth, ("SQL_Data_Table_" @ table @ "_TableContainer").width - 24); //("SQL_Data_Table_" @ table).minExtent = ("SQL_Data_Table_" @ table).baseWidth @ " " @ ("SQL_Data_Table_" @ table).height; //("SQL_Data_Table_" @ table).horizSizing = "width"; ("SQL_Data_Table_" @ table @ "_Columns").width = ("SQL_Data_Table_" @ table).width + 5; ("SQL_Data_Table_" @ table @ "_Columns").bringToFront(); break; case "updateSyncSetting": SQL_Databases_SyncList.selectedSync = temp.data; SQL_Databases_SyncList.active = true; SQL_Databases_SyncList.alpha = 1; break; case "defragDatabase": SQL_Databases_Defrag.active = true; break; case "getNewPage": temp.db = data[0][0]; temp.table = data[0][1]; temp.start = data[1]; temp.tRows = data[2]; temp.numRows = data[3]; temp.scroll = null; for (temp.tab : SQL_Data_Tabs.rows) { if (tab.text == (db @ "." @ table)) { scroll = tab.scroll; break; } } if (scroll == null) { break; } temp.con = scroll.con; temp.table = con.table; if (table.filter.size() > 0) { con.filterO.fValue.active = false; con.filterO.fX.active = true; con.filterO.fGo.active = false; } else { con.filterO.fValue.active = true; con.filterO.fX.active = false; con.filterO.fGo.active = true; } temp.shouldScroll = con.start != start; con.start = start; table.start = start; with (table) { clearRows(); temp.m = 0; for (temp.row : tRows) { temp.line = row[0]; for (temp.c = 1; c < row.size(); c ++) { line @= "\t" @ row[c]; if (m >= 9999) { m = 0; sleep(0.05); } m ++; } temp.r = addRow(0, line); r.rowid = row[0]; } } con.lB.active = start > 0; con.rB.active = start + tRows.size() < numRows; con.rowCount.text = "<center>Viewing rows " @ this.separate(start + 1) @ "-" @ this.separate(start + tRows.size()) @ " of " @ this.separate(numRows) @ "</center>"; table.parent.height = table.height + 27; if (shouldScroll) { table.parent.parent.scrollToTop(); } for (temp.div : table.parent.parent.dividers2) { div.height = table.height; } break; case "getCreateIndexColumns": temp.db = data[0][0]; temp.table = data[0][1]; temp.cols = data[1]; new GuiWindowCtrl("SQL_AddIndex_Window") { profile = GuiBlueWindowProfile; width = 240; height = 150; x = GraalControl.width / 2 - (width / 2); y = GraalControl.height / 2 - (height / 2); canClose = canMove = clientRelative = destroyOnClose = visible = true; isExternal = SQL_Window.isExternal; canMinimize = canMaximize = canResize = false; text = "Create Index"; this.tbl = {db, table}; showTop(); new GuiMLTextCtrl("SQL_AddIndex_Text") { profile = GuiBlueMLTextProfile; width = 215; x = 3; y = 2; text = "<center>Creating index on table '" @ db @ "." @ table @ "'\nIndex Name:</center>"; } new GuiTextEditCtrl("SQL_AddIndex_Name") { profile = GuiBlueTextEditProfile; width = 222; height = 20; x = 3; y = 33; text = "idx_" @ table @ "_"; } new GuiMLTextCtrl("SQL_AddIndex_Text2") { profile = GuiBlueMLTextProfile; width = 215; x = 3; y = 55; text = "<center>Column:</center>"; } new GuiPopUpMenuCtrl("SQL_AddIndex_Column") { profile = GuiBluePopUpMenuProfile; scrollprofile = GuiBlueScrollProfile; textprofile = GuiBlueTextListProfile; width = 222; height = 20; x = 3; y = 70; clearRows(); for (temp.c : cols) { addRow(0, c); } setSelectedRow(0); } new GuiButtonCtrl("SQL_AddIndex_Create") { profile = GuiBlueButtonProfile; width = 220; height = 23; x = 4; y = 93; text = "Add Index"; } } break; case "getRowContentsForModify": temp.db = data[0][0]; temp.table = data[0][1]; temp.rowid = data[1]; temp.columns = data[2]; temp.vals = data[3]; temp.start = data[4]; temp.scroll = null; for (temp.tab : SQL_Data_Tabs.rows) { if (tab.text == (db @ "." @ table)) { scroll = tab.scroll; break; } } if (scroll == null) { break; } temp.con = scroll.con; temp.tableO = con.table; showInsertRow({db, table}, columns, start, rowid, vals, tableO); break; case "getRowContentsForInsert": temp.db = data[0][0]; temp.table = data[0][1]; temp.columns = data[1]; temp.start = data[2]; temp.scroll = null; for (temp.tab : SQL_Data_Tabs.rows) { if (tab.text == (db @ "." @ table)) { scroll = tab.scroll; break; } } if (scroll == null) { break; } temp.con = scroll.con; temp.tableO = con.table; showInsertRow({db, table}, columns, start, NULL, NULL, tableO); break; } } function showInsertRow(loc, cols, start, rowid, vals, tblO) { temp.db = loc[0]; temp.table = loc[1]; if (isObject("SQL_Insert_Window")) { SQL_Insert_Window.destroy(); } new GuiWindowCtrl("SQL_Insert_Window") { profile = GuiBlueWindowProfile; width = 240; height = 200; minExtent = "160 160"; x = GraalControl.width / 2 - (width / 2); y = GraalControl.height / 2 - (height / 2); canMinimize = canMaximize = canResize = canClose = visible = clientRelative = true; isExternal = SQL_Window.isExternal; text = rowid > 0 ? "Modify Row" : "Insert Row"; this.tbl = {db, table}; this.st = start; this.r = rowid; this.tableO = tblO; new GuiMLTextCtrl("SQL_Insert_Text") { profile = GuiBlueMLTextProfile; width = 222; x = 3; y = 3; horizSizing = "width"; text = rowid > 0 ? "<center>Modifying row '" @ rowid @ "' in table '" @ db @ "." @ table @ "':" : "<center>Inserting row into table '" @ db @ "." @ table @ "':</center>"; } new GuiScrollCtrl("SQL_Insert_Scroll") { profile = GuiBlueScrollProfile; useownprofile = true; profile.border = 1; width = 220; height = 120; x = 4; y = 20; hScrollBar = "alwaysOff"; vScrollBar = "alwaysOn"; horizSizing = "width"; vertSizing = "height"; temp.c = 0; temp.scroll = this; for (temp.col : cols) { new GuiControl("SQL_Insert_Column_" @ c) { useownprofile = true; profile.opaque = true; profile.fillColor = c % 2 == 1 ? "199 219 226" : "153 184 202"; width = 200; height = 42; x = 0; y = c * height; horizSizing = "width"; temp.cont = this; scroll.cs.add(this); new GuiTextCtrl(name @ "_Text") { profile = GuiBlueTextProfile; useownprofile = true; profile.fontColor = "0 0 0"; width = 200; x = 3; y = 0; text = col @ ":"; } new GuiRadioCtrl(name @ "_ValueR") { profile = GuiBlueRadioProfile; useownprofile = true; profile.fontColor = profile.fontColorHL = "0 0 0"; width = 100; x = 105; y = (- 6); horizSizing = "left"; text = " Value"; group = 1; checked = true; cont.vr = this; thiso.catchEvent(this, "onAction", "onRadioValue"); } new GuiRadioCtrl(name @ "_NullR") { profile = GuiBlueRadioProfile; useownprofile = true; profile.fontColor = profile.fontColorHL = "0 0 0"; width = 100; x = 160; y = (- 6); horizSizing = "left"; text = " Null"; group = 1; cont.nr = this; thiso.catchEvent(this, "onAction", "onRadioNull"); } new GuiTextEditCtrl(name @ "_Value") { profile = GuiBlueTextEditProfile; width = 193; height = 20; x = 3; y = 19; horizSizing = "width"; cont.v = this; if (rowid > 0) { text = vals[c]; } else { text = ""; } } } c ++; } } new GuiButtonCtrl("SQL_Insert_Button") { profile = GuiBlueButtonProfile; x = 4; y = 144; width = 220; height = 22; vertSizing = "top"; horizSizing = "width"; text = rowid > 0 ? "Save" : "Insert"; } } } function onFilterXButtonClicked(button) { temp.filter = button.parent; temp.con = filter.parent.con; temp.table = con.table; table.filter = NULL; pageButton(con.lB, 0); button.active = false; } function formatSize(temp.bytes) { if (temp.bytes < 1048576) { return this.separate(int(temp.bytes / 1024 * 10) / 10) @ " KB"; } return this.separate(int(temp.bytes / 1048576 * 10) / 10) @ " MB"; } // credit to fowlplay4 (http://forums.graalonline.com/forums/showthread.php?p=1643646) function separate(val, sep) { // Set chars to separate numbers by temp.chars = 3; // Negative Number Support if (val < 0) { val *= -1; temp.negative = true; } else { temp.negative = false; } // Check if requires separation if (val >= (10 ^ temp.chars)) { // Decimal Support temp.dpos = val.pos("."); if (temp.dpos >= 0) { temp.newval = val.substring(temp.dpos); } else { temp.dpos = val.length(); } // Begin Separating Numbers for (temp.i = temp.dpos - temp.chars; temp.i > 0; temp.i -= temp.chars) { temp.newval = (sep ? sep : ",") @ val.substring(temp.i, temp.chars) @ temp.newval; } // Append Final Section of Number temp.newval = val.substring(0, temp.chars - abs(temp.i)) @ temp.newval; // Make negative if neccesary if (temp.negative) temp.newval = "-" @ temp.newval; // Return Separated Value return temp.newval; } else { // Make negative if neccesary and return value return val * (temp.negative ? -1 : 1); } } function onFilterButtonClicked(button) { temp.filter = button.parent; temp.con = filter.parent.con; temp.table = con.table; table.filter = {filter.fColumns.getSelectedText(), filter.fCompare.getSelectedText(), filter.fValue.text}; pageButton(con.lB, 0); button.active = false; filter.fValue.active = false; } function SQL_Insert_Button.onAction() { temp.table = SQL_Insert_Window.tbl; temp.rowid = SQL_Insert_Window.r; temp.tableO = SQL_Insert_Window.tableO; temp.columns = null; for (temp.col : SQL_Insert_Scroll.cs) { temp.value = col.v.text; temp.nullr = col.nr.checked; temp.valuer = col.vr.checked; columns.add({valuer, value}); } echo("cols="@columns); if (SQL_Insert_Button.text == "Insert") { tellServer("doInsertRow", {table, columns, SQL_Insert_Window.st, tableO.sortCMode, tableO.filter}); } else { tellServer("doModifyRow", {table, rowid, columns, SQL_Insert_Window.st, tableO.sortCMode, tableO.filter}); } SQL_Insert_Window.destroy(); } function onRadioValue(radio) { temp.cont = radio.parent; cont.v.alpha = 1; cont.v.active = true; } function onRadioNull(radio) { temp.cont = radio.parent; cont.v.alpha = .8; cont.v.active = false; } function onColumnClicked(columns, keymod, dx, dy, clicks) { if (clicks % 2 == 0) { temp.table = columns.parent.table; temp.cols = table.colDim; temp.cNames = table.colNames; temp.selectedCol = ""; temp.co = table.globalToLocalCoord({dx, dy}); temp.realX = co[0]; temp.c = 0; for (temp.col : cols) { if (realX < col) { selectedCol = cNames[c - 1]; break; } c ++; } if (selectedCol == "") { return; // clicked outside the columns } temp.oldColumnText = columns.sortColumn; oldColumnText.text = oldColumnText.realText; temp.newColumnText = columns.dividerTexts[cNames.index(@ selectedCol)]; newColumnText.text = "<b>" @ newColumnText.realText @ "</b>"; columns.sortColumn = newColumnText; temp.oldSortMode = table.sortCMode; if (oldSortMode[0] == selectedCol) { table.sortCMode[1] = ! table.sortCMode[1]; // reverse ascending/descending } else { table.sortCMode = {selectedCol, 0}; } temp.scroll = columns.parent.parent; pageButton(scroll.con.lB, 0); } } function onTableRightClicked(table, rowid, rowtext, rowindex) { temp.row = table.rows[rowindex]; temp.rowid = row.rowid; temp.options = {"Insert Row", "Modify Row", "Duplicate Row", "Delete Row"}; if (table.objectType() == "GuiControl") { // columns options = {"Insert Row"}; } else { temp.selectedRows = table.getSelectedRows(); if (temp.selectedRows.size() > 1) { options = {"Insert Row", "Delete Rows"}; temp.rowid = null; for (temp.selectedRowIndex : temp.selectedRows) { temp.rowid.add(table.rows[temp.selectedRowIndex].rowid); } } } new GuiContextMenuCtrl("SQL_Data_Table_Menu") { profile = GuiBlueContextMenuProfile; textprofile = GuiBlueTextListProfile; scrollprofile = SQLContextScrollProfile; this.sRow = rowid; this.tbl = table.tbl; this.tableO = table; this.st = table.start; this.db = table.database; clearRows(); for (temp.option : options) { addRow(0, option); } openAtMouse(); } } function SQL_Data_Table_Menu.onSelect(rowid, rowtext, rowindex) { temp.table = SQL_Data_Table_Menu.tbl; temp.db = SQL_Data_Table_Menu.db; temp.tableO = SQL_Data_Table_Menu.tableO; temp.rowid = SQL_Data_Table_Menu.sRow; temp.start = SQL_Data_Table_Menu.st; switch (rowtext) { case "Insert Row": getServer("getRowContentsForInsert", {{db, table}, start}); break; case "Modify Row": getServer("getRowContentsForModify", {{db, table}, rowid, start}); break; case "Duplicate Row": tellServer("doDuplicateRow", {{db, table}, rowid, start, tableO.sortCMode, tableO.filter}); break; case "Delete Row": ask2("Are you sure you want to delete row '" @ rowid @ "'?", "Yes", "No", "onDeleteRow", {{db, table}, {rowid}, start, tableO}); break; case "Delete Rows": temp.str = ""; for (temp.r : temp.rowid) { temp.str @= temp.r @ ", "; } temp.last = temp.rowid[temp.rowid.size() - 1]; temp.str = temp.str.substring(0, temp.str.length() - (2 + temp.last.length())); if (temp.str.ends(", ")) { temp.str = temp.str.substring(0, temp.str.length() - 2) @ " "; } temp.str @= "and " @ temp.last; ask2("Are you sure you want to delete rows " @ temp.str @ "?", "Yes", "No", "onDeleteRow", {{db, table}, rowid, start, tableO}); break; } } function onDeleteRow(data, f) { if (f) { // clicked "no" return; } temp.table = data[0]; temp.rowid = data[1]; temp.start = data[2]; temp.realTable = data[3]; tellServer("doDeleteRows", {table, rowid, start, realTable.sortCMode, realTable.filter}); } function SQL_AddIndex_Create.onAction() { temp.table = SQL_AddIndex_Window.tbl; temp.column = SQL_AddIndex_Column.getSelectedText(); temp.idx = SQL_AddIndex_Name.text; tellServer("doCreateIndex", {table, column, idx}); SQL_AddIndex_Window.destroy(); } function onPageLeft(button) { pageButton(button, -1); } function onPageRight(button) { pageButton(button, 1); } function pageButton(button, dir) { // (-1)=left, 1=right temp.con = button.parent.parent.con; temp.table = con.tbl; temp.db = con.database; temp.start = con.start; temp.tableO = con.table; getServer("getNewPage", {{db, table}, start, dir, tableO.sortCMode, tableO.filter}); } function onMouseOverDivider(div) { div.profile.borderColor = "120 120 120"; } function onMouseLeavesDivider(div) { if (div == this.dragging) { return; } div.profile.borderColor = "0 0 0"; } function onMouseDragsDivider(div) { if (this.dragging != null) { return; } this.dragging = div; this.draggingx = mousescreenx; onTimeOut(); } function onTimeOut() { if (this.dragging == null) { return; } if (mousescreenx != this.draggingx) { temp.p = this.dragging.parent.globalToLocalCoord({mousescreenx, this.dragging.parent.y + 2}); this.draggingx = mousescreenx; temp.con = this.dragging.parent.parent; // container temp.table = con.table; temp.cols = table.colDim; px = max(p[0], cols[this.dragging.columnNum - 1] + this.dragging.myMin); if (px != this.dragging.x) { temp.dif = px - this.dragging.x; this.dragging.x = px; temp.num = this.dragging.columnNum; temp.newCols = null; for (temp.i = 0; i < cols.size(); i ++) { if (i < num) { newCols.add(cols[i]); } else { newCols.add(cols[i] + dif); } } for (temp.i = 0; i < con.dividers.size(); i ++) { temp.div = con.dividers[i]; if (div.columnNum <= num) { continue; } div.x += dif; } for (temp.i = 0; i < con.dividerTexts.size(); i ++) { temp.div = con.dividerTexts[i]; if (div.columnNum < num) { continue; } div.x += dif; con.dividers2[i - 1].x += dif; } table.columns = newCols; table.colDim = newCols; } } if (! leftmousebuttonglobal) { this.dragging.profile.borderColor = "0 0 0"; this.dragging = null; return; } setTimer(0.05); } function onTableResized(container, nWidth) { temp.columns = container.columns; temp.list = container.table; temp.tc = container.tc; tc.width = max(list.baseWidth, container.width - 24); list.width = tc.width; columns.width = list.width + 5; } function onScrollUp(scroll) { scroll.parent.parent.scrollDelta(0, (- 20)); } function onScrollDown(scroll) { scroll.parent.parent.scrollDelta(0, 20); } function onContainerScrolled(container) { container.columns.y = container.scrollpos[1] - 2; } function startFileDownloads() { temp.filesToDownload = { {"sqlexplorer_database-big.png", "http://wiki.graal.net/images/3/33/DatabaseSmall.png"}, {"sqlexplorer_database-small.png", "http://wiki.graal.net/images/d/d2/DatabaseIcon.png"}, {"sqlexplorer_loading.gif", "http://wiki.graal.net/images/a/a7/GuiBlueLoading.gif"} }; for (temp.fileToDownload : temp.filesToDownload) { if (true || getimgwidth(temp.fileToDownload[0]) <= 0) { // download it this.downloadFile(temp.fileToDownload); } } } function downloadFile(temp.fileToDownload) { temp.req = requestURL(temp.fileToDownload[1]); temp.req.fileName = temp.fileToDownload[0]; this.catchEvent(temp.req, "onReceiveData", "onDownloadCompleted"); } function onDownloadCompleted(temp.req) { temp.prefix = ""; if (getServerName().starts("Login")) { temp.prefix = "scriptfiles/" @ escapeFileName(getServerName()) @ "/"; } temp.req.fullData.saveString(temp.prefix @ temp.req.fileName, false); } function showExplorer() { this.startFileDownloads(); if (isObject("SQL_Window")) { if (SQL_Window.visible) { return SQL_Window.showTop(); } SQL_Window.destroy(); } getServer("getDatabases"); new GuiWindowCtrl("SQL_Window") { profile = GuiBlueWindowProfile; width = SIZE_INIT_W; height = SIZE_INIT_H; x = GraalControl.width / 2 - (width / 2); y = GraalControl.height / 2 - (height / 2); minExtent = MIN_W @ " " @ MIN_H; canClose = canMinimize = canMaximize = canResize = clientRelative = true; isExternal = player.client.option.staff.sql_explorer.isexternal; text = "SQL Explorer " @ VERSION; new GuiControl("SQL_Container") { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = "0 0 0 20"; width = SQL_Window.clientwidth + 2; height = SQL_Window.clientheight + 2; x = (- 1); y = (- 1); horizSizing = "width"; vertSizing = "height"; new GuiTabCtrl("SQL_Tabs") { profile = GuiBlueTabProfile; x = 20; y = 0; width = SQL_Window.clientwidth - x; height = 20; tabwidth = 100; horizSizing = "width"; clearRows(); } // external window toggle new GuiControl("SQL_ExternalToggle") { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = {255, 255, 255, 100}; x = 0; y = 0; width = 21; height = 21; hint = "Toggle between inside and outside the game window."; new GuiMLTextCtrl("SQL_ExternalToggle_Text") { profile = GuiBlueTextProfile; useOwnProfile = true; profile.fontColor = {0, 0, 0}; profile.modal = false; x = 0; y = 3; width = 20; height = 18; text = "<center>=</center>"; } } // "Data" tab new GuiControl("SQL_Data_Container") { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = "0 0 0 20"; x = (- 1); y = 20; width = SQL_Container.width + 1; height = SQL_Container.height - 20; visible = false; horizSizing = "width"; vertSizing = "height"; temp.tab = SQL_Tabs.addRow(0, "Data"); tab.scroll = this; new GuiTabCtrl("SQL_Data_Tabs") { profile = GuiBlueTabProfile; width = SQL_Data_Container.width - 22; height = 20; x = 1; y = 0; tabwidth = 120; horizSizing = "width"; clearRows(); } new GuiButtonCtrl("SQL_Data_CloseTab") { profile = GuiBlueButtonProfile; width = 20; height = 20; x = SQL_Data_Container.width - 20; y = 0; horizSizing = "left"; text = "-"; hint = "Close the current tab"; } } // "Execute SQL" tab -- thanks to fowlplay4 for much of this new GuiControl("SQL_Execute_Container") { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = "0 0 0 20"; x = (- 1); y = 20; width = SQL_Container.width + 1; height = SQL_Container.height - 20; visible = false; horizSizing = "width"; vertSizing = "height"; temp.tab = SQL_Tabs.addRow(0, "Execute SQL"); tab.scroll = this; temp.sc = this; new GuiTextCtrl("SQL_Execute_Database_Label") { profile = GuiBlueTextProfile; width = 60; height = 20; x = 6; y = 5; text = "Database:"; } new GuiPopUpMenuCtrl("SQL_Execute_Database") { profile = GuiBluePopUpMenuProfile; textprofile = GuiBlueTextListProfile; scrollprofile = GuiBlueScrollProfile; x = 70; y = 6; width = sc.width - x - 5; height = 20; horizSizing = "width"; this.clearRows(); this.addRow(0, "Loading..."); this.setSelectedRow(0); this.active = false; } new GuiFrameSetCtrl("SQL_Execute_Frames") { profile = GuiBlueFrameSetProfile; width = sc.width - 11; height = sc.height - 61; x = 6; y = 30; rowcount = 2; columncount = 1; horizSizing = "width"; vertSizing = "height"; new GuiScrollCtrl("SQL_Execute_QueryContainer") { profile = GuiBlueScrollProfile; useownprofile = true; profile.border = 1; minExtent = "0 70"; vScrollBar = "dynamic"; hScrollBar = "dynamic"; new GuiMLTextEditCtrl("SQL_Execute_Query") { profile = GuiBlueMLTextEditProfile; width = SQL_Execute_QueryContainer.width - 24; x = 2; y = 0; horizSizing = "width"; } } new GuiScrollCtrl("SQL_Execute_ConsoleContainer") { profile = GuiBlueScrollProfile; useownprofile = true; profile.border = 1; minExtent = "0 70"; vScrollBar = "dynamic"; hScrollBar = "dynamic"; new GuiMLTextCtrl("SQL_Execute_Console") { profile = GuiBlueMLTextEditProfile; useownprofile = true; profile.fontType = "Courier"; width = SQL_Execute_ConsoleContainer.width - 24; wordwrap = false; x = 2; y = 0; horizSizing = "width"; text = "Welcome to SQL Explorer " @ VERSION; } } } temp.c = 0; for (temp.b : {"Execute Query", "Clear Query", "Clear Console"}) { new GuiButtonCtrl("SQL_Execute_Button_" @ c) { profile = GuiBlueButtonProfile; width = (sc.width - 20) / 3; height = 22; x = 5 + (c * (5 + width)); y = sc.height - 27; text = b; vertSizing = "top"; if (c == 0) { horizSizing = "right"; } else if (c == 2) { horizSizing = "left"; } else { horizSizing = "center"; } thiso.catchEvent(this, "onAction", "onExecuteButton"); } c ++; } } // "Databases" tab new GuiControl("SQL_Databases_Container") { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = "0 0 0 20"; x = (- 1); y = 20; width = SQL_Container.width + 1; height = SQL_Container.height - 20; visible = false; horizSizing = "width"; vertSizing = "height"; temp.tab = SQL_Tabs.addRow(0, "Databases"); tab.scroll = this; temp.sc = this; new GuiMLTextCtrl("SQL_Databases_Info") { profile = GuiBlueMLTextProfile; x = 5; width = temp.sc.width - (x * 2); height = 56; y = temp.sc.height - height; horizSizing = "width"; vertSizing = "top"; text = "<center>To add another database to the server, adjust the list at the top of this script and add this line to server options:<br /><font face=\"Courier New\">database=database_name,database_file</font>"; } new GuiFrameSetCtrl("SQL_Databases_Frames") { profile = GuiBlueFrameSetProfile; width = sc.width - 11; height = sc.height - 65; x = 6; y = 5; rowcount = 1; columncount = 2; horizSizing = "width"; vertSizing = "height"; this.setColumnOffset(1, 175); new GuiScrollCtrl("SQL_Databases_ListScroll") { profile = GuiBlueScrollProfile; useownprofile = true; profile.border = 1; minExtent = "125 0"; vScrollBar = "dynamic"; hScrollBar = "dynamic"; new GuiTextListCtrl("SQL_Databases_List") { profile = GuiBlueTextListProfile; useOwnProfile = true; profile.modal = false; x = 0; y = 0; active = false; this.clearRows(); this.addRow(0, "Loading..."); } } new GuiScrollCtrl("SQL_Databases_DatabaseScroll") { profile = GuiBlueScrollProfile; useownprofile = true; profile.border = 1; minExtent = "200 0"; vScrollBar = "dynamic"; hScrollBar = "dynamic"; new GuiMLTextCtrl("SQL_Databases_DatabaseText") { profile = GuiBlueMLTextProfile; width = 200; x = 0; horizSizing = "center"; vertSizing = "center"; active = false; text = "<center>select a database on the left to view information about it</center>"; } new GuiShowImgCtrl("SQL_Databases_Loading") { image = "sqlexplorer_loading.gif"; width = 32; height = 32; horizSizing = "center"; vertSizing = "center"; active = false; visible = false; } // to easily hide/show new GuiControl("SQL_Databases_DatabaseInfo") { x = 0; y = 10; width = SQL_Databases_DatabaseScroll.width - 21; height = SQL_Databases_DatabaseScroll.height - 21; vertSizing = ""; horizSizing = "width"; visible = false; temp.infoControl = this; new GuiShowImgCtrl("SQL_Databases_DatabaseIcon") { x = 0; y = 10; width = 63; height = 60; image = "sqlexplorer_database-big.png"; horizSizing = "center"; } new GuiMLTextCtrl("SQL_Databases_DatabaseLabel") { profile = GuiBlueMLTextProfile; width = temp.infoControl.width; horizSizing = "width"; active = false; x = 0; y = SQL_Databases_DatabaseIcon.y + SQL_Databases_DatabaseIcon.height + 5; text = "<center><b>default"; } temp.keys = {"Database File", "Database Size", "Table Count", "Synchronous"}; temp.i = 0; for (temp.key : temp.keys) { new GuiMLTextCtrl("SQL_Databases_DatabaseInfo_" @ temp.i) { profile = GuiBlueMLTextProfile; x = 0; y = SQL_Databases_DatabaseLabel.y + 22 + (temp.i * 16); text = "<center><b>" @ temp.key @ ":</b> 32"; width = temp.infoControl.width; active = false; horizSizing = "width"; } temp.i ++; } new GuiControl("SQL_Databases_Sync") { y = SQL_Databases_DatabaseInfo_3.y + 20; width = 103; height = 20; horizSizing = "center"; new GuiPopUpMenuCtrl("SQL_Databases_SyncList") { profile = GuiBluePopUpMenuProfile; scrollprofile = GuiBlueScrollProfile; textprofile = GuiBlueTextListProfile; x = 0; y = 0; width = 80; height = 20; this.clearRows(); this.addRow(0, "Off"); this.addRow(1, "Normal"); this.addRow(2, "Full"); } new GuiButtonCtrl("SQL_Databases_SyncHelp") { profile = GuiBlueButtonProfile; width = 19; height = 18; x = 84; y = 1; text = "?"; } } new GuiButtonCtrl("SQL_Databases_Defrag") { profile = GuiBlueButtonProfile; width = 150; height = 23; y = SQL_Databases_Sync.y + SQL_Databases_Sync.height + 10; text = "Defragment"; horizSizing = "center"; SQL_Databases_DatabaseInfo.height = y + height + 5; } } } } } // end databases tab } } SQL_Tabs.setSelectedRow(0); with (addDataTab("Structure")) { temp.par = this; vScrollBar = "alwaysOff"; hScrollBar = "alwaysOff"; new GuiScrollCtrl("SQL_Data_DBs_TreeContainer") { profile = GuiBlueScrollProfile; width = par.width; height = par.height - 35; x = (- 2); y = (- 2); vertSizing = "height"; horizSizing = "width"; vScrollBar = "dynamic"; hScrollBar = "dynamic"; new GuiTreeViewCtrl("SQL_Data_DBs_Tree") { profile = GuiBlueTreeViewProfile; x = 0; y = 0; fitparentwidth = true; horizSizing = "width"; active = false; clearNodes(); addNode("Loading..."); } } new GuiControl("SQL_Data_DBs_RefreshContainer") { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = {255, 255, 255, 70}; width = par.width; height = 35; x = (- 2); y = par.height - height - 3; horizSizing = "width"; vertSizing = "top"; /*new GuiButtonCtrl("SQL_Data_DBs_Add") { // removed for multiple DBs profile = GuiBlueButtonProfile; width = 25; height = 25; x = 5; y = 5; text = "+"; }*/ new GuiButtonCtrl("SQL_Data_DBs_Refresh") { profile = GuiBlueButtonProfile; width = par.width - 10; height = 25; x = 5; y = 5; text = "Refresh"; active = false; horizSizing = "width"; } } } } function SQL_Databases_Defrag.onAction() { this.getServer("defragDatabase", SQL_Databases_List.rows[SQL_Databases_List.getSelectedRow()].dbName); SQL_Databases_Defrag.active = false; } function SQL_Databases_SyncList.onSelect(temp.entryID, temp.entryText, temp.entryIndex) { if (SQL_Databases_SyncList.selectedSync == temp.entryIndex) { return; } SQL_Databases_SyncList.active = false; SQL_Databases_SyncList.alpha = 0.6; this.getServer("updateSyncSetting", {SQL_Databases_List.rows[SQL_Databases_List.getSelectedRow()].dbName, temp.entryIndex}); } function SQL_Databases_List.onSelect(temp.entryID, temp.entryText, temp.entryIndex) { SQL_Databases_DatabaseText.visible = false; SQL_Databases_DatabaseInfo.visible = false; SQL_Databases_Loading.visible = true; SQL_Databases_List.active = false; this.getServer("getDatabaseInfo", SQL_Databases_List.rows[temp.entryIndex].dbName); } function SQL_ExternalToggle.onMouseEnter() { SQL_ExternalToggle.profile.fillColor = {255, 255, 255, 150}; } function SQL_ExternalToggle.onMouseLeave() { SQL_ExternalToggle.profile.fillColor = {255, 255, 255, 100}; } function SQL_ExternalToggle.onMouseDown() { SQL_Window.isExternal = ! SQL_Window.isExternal; player.client.option.staff.sql_explorer.isexternal = SQL_Window.isExternal; } function onExecuteButton(button) { switch (button.text) { case "Clear Console": SQL_Execute_Console.text = ""; break; case "Clear Query": SQL_Execute_Query.text = ""; break; case "Execute Query": temp.q = ""; for (temp.line : SQL_Execute_Query.getLines()) { q @= line; } q = q.trim(); if (q == null) { break; } tellServer("doExecuteQuery", {SQL_Execute_Database.getText(), q}); break; } } function executeResults(columns, rows) { sqlEcho("\n" @ this.separate(rows.size()) @ " rows returned"); temp.max = null; for (temp.col : columns) { max.add(col.length()); } temp.i = 0; for (temp.row : rows) { i ++; temp.c = 0; for (temp.col : row) { i ++; if (max[c] < col.length()) { max[c] = col.length(); } c ++; if (i % 9000 == 0) { sleep(0.05); // avoid max loop limit } } } temp.e = ""; temp.c = 0; for (temp.col : columns) { i ++; e @= "|" @ col @ spaces(max[c] - col.length()); c ++; if (i % 9000 == 0) { sleep(0.05); // avoid max loop limit } } e @= "|"; sqlEcho(e); temp.b = ""; for (temp.i = 0; i < e.length(); i ++) { i ++; b @= "-"; if (i % 9000 == 0) { sleep(0.05); // avoid max loop limit } } sqlEcho(b); for (temp.row : rows) { i ++; temp.cb = ""; temp.z = 0; for (temp.col : row) { i ++; if (i % 9000 == 0) { sleep(0.05); // avoid max loop limit } cb @= "|" @ col @ spaces(max[z] - col.length()); z ++; } cb @= "|"; sqlEcho(cb); } } function sqlEcho(msg) { if (SQL_Execute_Console.text != null) { SQL_Execute_Console.text @= "\n" @ msg; } else { SQL_Execute_Console.text = msg; } } function SQL_Databases_SyncHelp.onAction() { openURL("http://pastebin.graalcenter.org/read.php?id=12140838206"); } function spaces(x) { temp.str = ""; for (temp.i = 0; i < x; i ++) { if ((i + 1) % 9000 == 0) { sleep(0.05); // avoid max loop limit } str @= " "; } return str; } /*function SQL_Data_DBs_Add.onAction() { showNewTable(); }*/ function SQL_Data_DBs_Tree.onOpenMenu(node) { temp.options = null; if (node.level == 1) { // database options = {"Create Table"}; } else if (node.level == 2) { // table options = {node.database @ "." @ node.text, "-", "Drop Table", "Rename Table", "Duplicate Table", "Get Schema", "-", "Create Index", "Add Column"}; } else if (node.level == 3) { // index options = {node.parent.database @ "." @ node.indexName @ " (" @ node.parent.text @ ")", "-", "Drop Index", "Get Schema"}; } new GuiContextMenuCtrl("SQL_Data_DBs_Tree_Menu") { profile = GuiBlueContextMenuProfile; textprofile = GuiBlueTextListProfile; scrollprofile = SQLContextScrollProfile; this.sNode = node; clearRows(); for (temp.option : options) { addRow(0, option); } openAtMouse(); } } function SQL_Data_DBs_Tree_Menu.onSelect(entryid, entrytext, entryindex) { temp.node = SQL_Data_DBs_Tree_Menu.sNode; if (node == null) { return; } if (node.level == 1) { switch (entrytext) { case "Create Table": showNewTable(node.text); break; } } else if (node.level == 2) { // table switch (entrytext) { case "Drop Table": ask2("Are you sure you want to drop the table '" @ node.text @ "'?", "Yes", "No", "onDropTable", {node.parent.text, node.text}); break; case "Rename Table": ask("What would you like to rename the table '" @ node.text @ "' to?", "Rename", "onRenameTable", {node.parent.text, node.text}); break; case "Duplicate Table": ask("What would you like the duplicate of the table '" @ node.text @ "' to be called?", "Create", "onDupeTable", {node.parent.text, node.text}); break; case "Create Index": getServer("getCreateIndexColumns", {node.parent.name, node.text}); break; case "Add Column": showNewColumn({node.parent.name, node.text}); break; case "Get Schema": tellServer("doGetTableSchema", {node.parent.text, node.text}); break; } } else if (node.level == 3) { // index switch (entrytext) { case "Drop Index": ask2("Are you sure you want to drop the index '" @ node.indexName @ "'?", "Yes", "No", "onDropIndex", {node.parent.parent.text, node.indexName}); break; case "Get Schema": tellServer("doGetIndexSchema", {node.parent.parent.text, node.indexName}); break; } } } function showNewColumn(tbl) { new GuiWindowCtrl("SQL_AddCol_Window") { profile = GuiBlueWindowProfile; width = 250; height = 177; x = GraalControl.width / 2 - (width / 2); y = GraalControl.height / 2 - (height / 2); canClose = canMove = clientRelative = destroyOnClose = visible = true; isExternal = SQL_Window.isExternal; canMinimize = canMaximize = canResize = false; text = "Add Column"; this.table = tbl; showTop(); new GuiMLTextCtrl("SQL_AddCol_Text") { profile = GuiBlueMLTextProfile; width = 232; x = 3; y = 3; text = "<center>What would you like the new column on table '" @ tbl[0] @ "." @ tbl[1] @ "' to be called?</center>"; } new GuiTextCtrl("SQL_AddCol_Name_Label") { profile = GuiBlueTextProfile; x = 5; y = 36; text = "Name:"; } new GuiTextEditCtrl("SQL_AddCol_Name") { profile = GuiBlueTextEditProfile; width = 199; height = 20; x = 36; y = 36; text = ""; } new GuiTextCtrl("SQL_AddCol_Type_Label") { profile = GuiBlueTextProfile; x = 5; y = 57; text = "Type:"; } new GuiPopUpMenuCtrl("SQL_AddCol_Type") { profile = GuiBluePopUpMenuProfile; scrollprofile = GuiBlueScrollProfile; textprofile = GuiBlueTextListProfile; width = 199; height = 20; x = 36; y = 57; temp.types = {"Text", "Real", "Integer", "Blob"}; clearRows(); for (temp.t : types) { addRow(0, t); } setSelectedRow(0); } new GuiTextCtrl("SQL_AddCol_Default_Label") { profile = GuiBlueTextProfile; x = 5; y = 78; text = "Default:"; } new GuiTextEditCtrl("SQL_AddCol_Default") { profile = GuiBlueTextEditProfile; width = 150; height = 20; x = 43; y = 78; horizSizing = "width"; } new GuiCheckBoxCtrl("SQL_AddCol_DefNull") { profile = GuiBlueCheckBoxProfile; width = 50; height = 17; x = 198; y = 80; text = " Null"; checked = false; } /*new GuiCheckBoxCtrl("SQL_AddCol_Unique") { profile = GuiBlueCheckBoxProfile; width = 50; height = 17; x = 6; y = 101; text = " Unique"; } new GuiCheckBoxCtrl("SQL_AddCol_AutoInc") { profile = GuiBlueCheckBoxProfile; width = 100; height = 17; x = 63; y = 101; text = " Auto Increment"; }*/ new GuiCheckBoxCtrl("SQL_AddCol_NotNull") { profile = GuiBlueCheckBoxProfile; width = 70; height = 17; x = 6; y = 101; text = " Not Null"; checked = false; } new GuiButtonCtrl("SQL_AddCol_Create") { profile = GuiBlueButtonProfile; width = 230; height = 23; x = 4; y = 120; text = "Add Column"; } } } function SQL_AddCol_Create.onAction() { // name, type, default, default is null, unique, auto_inc, not null temp.col = {SQL_AddCol_Name.text, SQL_AddCol_Type.getSelectedText(), SQL_AddCol_Default.text, SQL_AddCol_DefNull.checked, false, false, SQL_AddCol_NotNull.checked}; tellServer("doAddColumn", {SQL_AddCol_Window.table, col}); SQL_AddCol_Window.destroy(); } function onDropTable(tbl, f) { if (f) { // no return; } tellServer("doDropTable", tbl); } function onRenameTable(tbl, newName) { tellServer("doRenameTable", {tbl, newName}); } function onDupeTable(tbl, newName) { tellServer("doDuplicateTable", {tbl, newName}); } function onDropIndex(idx, f) { if (f) { // no return; } tellServer("doDropIndex", idx); } function onAddColumn(tbl, newName) { tellServer("doAddColumn", {tbl, newName}); } function SQL_Data_DBs_Tree.onDblClick(node) { if (node.level != 2) { return; // double clicked an index or db :( } if (node.isWaiting) { return; // already asked serverside } temp.table = node.text; if (node.nodes.size() > 0) { node.expanded = ! node.expanded; } // check if there's already a tab for it temp.c = 0; for (temp.tab : SQL_Data_Tabs.rows) { if (tab.tableName == (node.database @ "." @ table)) { return SQL_Data_Tabs.setSelectedRow(c); } c ++; } node.isWaiting = true; getServer("getTable", {node.database, table}); } function SQL_Data_DBs_Refresh.onAction() { SQL_Data_DBs_Refresh.active = false; getServer("getDatabases"); with (SQL_Data_DBs_Tree) { clearNodes(); active = false; addNode("Loading..."); } } function SQL_Tabs.onSelect(rowid, rowtext, rowindex) { temp.scroll = SQL_Tabs.rows[rowindex].scroll; temp.msg = SQL_Tabs.rows[rowindex].displayMessage; if (temp.msg != null) { this.msg(temp.msg); SQL_Tabs.rows[rowindex].displayMessage = null; } SQL_Tabs.scroll.visible = false; SQL_Tabs.scroll = scroll; scroll.visible = true; } function SQL_Data_Tabs.onOpenMenu(rowindex, mx, my) { if (SQL_Data_Tabs.getSelectedRow() != rowindex || rowindex == 0) { return; // not selected or "tables" tab } temp.options = {"Refresh Table", "Close Tab"}; new GuiContextMenuCtrl("SQL_Data_Tabs_Menu") { profile = GuiBlueContextMenuProfile; textprofile = GuiBlueTextListProfile; scrollprofile = SQLContextScrollProfile; temp.tab = SQL_Data_Tabs.rows[rowindex]; this.tableName = tab.text; this.scroll = tab.scroll; clearRows(); for (temp.option : options) { addRow(0, option); } openAtMouse(); } } function SQL_Data_Tabs_Menu.onSelect(rowid, rowtext, rowindex) { temp.menu = SQL_Data_Tabs_Menu; temp.table = menu.tableName; switch (rowtext) { case "Refresh Table": temp.scroll = menu.scroll; pageButton(scroll.con.lB, 0); break; case "Close Tab": closeCurrentTab(); break; } } function SQL_Data_Tabs.onSelect(rowid, rowtext, rowindex) { temp.scroll = SQL_Data_Tabs.rows[rowindex].scroll; SQL_Data_Tabs.scroll.visible = false; SQL_Data_Tabs.scroll = scroll; scroll.visible = true; SQL_Data_CloseTab.active = rowindex != 0; } function SQL_Data_CloseTab.onAction() { closeCurrentTab(); } function closeCurrentTab() { SQL_Data_Tabs.rows[SQL_Data_Tabs.getSelectedRow()].scroll.destroy(); SQL_Data_Tabs.removeRow(SQL_Data_Tabs.getSelectedRow()); } function addDataTab(title, table) { temp.tabs = SQL_Data_Tabs; temp.tab = tabs.addRow(0, title); temp.scroll = null; tab.tableName = table; new GuiScrollCtrl("SQL_Data_" @ (tabs.tabid ++)) { profile = GuiBlueScrollProfile; useownprofile = true; profile.border = 1; profile.transparency = .5; x = 1; y = 20; width = SQL_Data_Container.width - 1; height = SQL_Data_Container.height - 20; horizSizing = "width"; vertSizing = "height"; visible = false; SQL_Data_Container.addControl(this); tab.scroll = this; scroll = this; } tabs.setSelectedRow(tabs.rows.size() - 1); return scroll; } function showNewTable(db) { // SQLNewT_Window.destroy(); // testing if (isObject("SQLNewT_Window")) { if (SQLNewT_Window.visible) { return SQLNewT_Window.showTop(); } SQLNewT_Window.destroy(); } new GuiWindowCtrl("SQLNewT_Window") { profile = GuiBlueWindowProfile; width = 300; height = 300; minExtent = "200 150"; x = GraalControl.width / 2 - (width / 2); y = GraalControl.height / 2 - (height / 2); canClose = canMinimize = canMaximize = canResize = clientRelative = true; isExternal = SQL_Window.isExternal; text = "Create Table (" @ db @ ")"; this.database = db; new GuiTextCtrl("SQLNewT_Name_Label") { profile = GuiBlueTextProfile; x = 4; y = 3; text = "Table Name:"; } new GuiTextEditCtrl("SQLNewT_Name") { profile = GuiBlueTextEditProfile; width = SQLNewT_Window.width - 80; height = 20; x = 65; y = 3; horizSizing = "width"; text = ""; } new GuiTextCtrl("SQLNewT_Columns_Label") { profile = GuiBlueTextProfile; x = 4; y = 27; text = "Columns:"; } new GuiButtonCtrl("SQLNewT_NewColumn") { profile = GuiBlueButtonProfile; width = 20; height = 15; x = SQLNewT_Window.width - width - 15; y = 28; horizSizing = "left"; text = "+"; } new GuiScrollCtrl("SQLNewT_Columns") { profile = GuiBlueScrollProfile; useownprofile = true; profile.border = 1; x = 3; y = 46; width = SQLNewT_Window.width - 18; height = SQLNewT_Window.height - y - 60; horizSizing = "width"; vertSizing = "height"; vScrollBar = "alwaysOn"; hScrollBar = "alwaysOff"; } new GuiButtonCtrl("SQLNewT_Create") { profile = GuiBlueButtonProfile; width = SQLNewT_Window.width - 18; height = 24; x = 3; y = SQLNewT_Window.height - 57; horizSizing = "width"; vertSizing = "top"; text = "Create Table"; } } } function SQLNewT_Create.onAction() { temp.table = SQLNewT_Name.text; temp.columns = null; for (temp.column : SQLNewT_Columns.cols) { if (column[0].trim() == "") { continue; } // name, type, default, default is null, unique, auto_inc, not null columns.add({column.sname.text, column.stype.getSelectedText(), column.sdefault.text, column.sdefnull.checked, column.sunique.checked, column.sauto.checked, column.snotnull.checked}); } tellServer("doCreateTable", {{SQLNewT_Window.database, table}, columns}); SQLNewT_Window.destroy(); } function SQLNewT_NewColumn.onAction() { addNewColumn(); } function addNewColumn() { with (SQLNewT_Columns) { temp.par = this; new GuiControl("SQLNewT_Column" @ this.colNum) { useownprofile = true; profile.border = 1; profile.opaque = true; profile.fillColor = par.cols.size() % 2 == 1 ? "199 219 226" : "153 184 202"; width = par.width - 18; height = 95; x = (- 2); y = par.cols[par.cols.size() - 1].y + par.cols[par.cols.size() - 1].height - 1; temp.col = this; horizSizing = "width"; new GuiTextCtrl(name @ "_Name_Label") { profile = GuiBlueTextProfile; useownprofile = true; profile.fontColor = "0 0 0"; x = 5; y = 4; text = "Name:"; } new GuiTextEditCtrl(name @ "_Name") { profile = GuiBlueTextEditProfile; width = col.width - 41; height = 20; x = 36; y = 4; horizSizing = "width"; col.sname = this; } new GuiTextCtrl(name @ "_Type_Label") { profile = GuiBlueTextProfile; useownprofile = true; profile.fontColor = "0 0 0"; x = 5; y = 27; text = "Type:"; } new GuiPopUpMenuCtrl(name @ "_Type") { profile = GuiBluePopUpMenuProfile; scrollprofile = GuiBlueScrollProfile; textprofile = GuiBlueTextListProfile; width = col.width - 41; height = 20; x = 36; y = 27; temp.types = {"Text", "Real", "Integer", "Blob"}; for (temp.t : types) { addRow(0, t); } //sort(); setSelectedRow(0); horizSizing = "width"; col.stype = this; } new GuiTextCtrl(name @ "_Default_Label") { profile = GuiBlueTextProfile; useownprofile = true; profile.fontColor = "0 0 0"; x = 5; y = 50; text = "Default:"; } new GuiTextEditCtrl(name @ "_Default") { profile = GuiBlueTextEditProfile; width = col.width - 87; height = 20; x = 43; y = 50; horizSizing = "width"; col.sdefault = this; } new GuiCheckBoxCtrl(name @ "_DefNull") { profile = GuiBlueCheckBoxProfile; useownprofile = true; profile.fontColor = "0 0 0"; width = 50; height = 17; x = col.width - 40; y = 52; horizSizing = "left"; text = " Null"; col.sdefnull = this; } new GuiCheckBoxCtrl(name @ "_Unique") { profile = GuiBlueCheckBoxProfile; useownprofile = true; profile.fontColor = "0 0 0"; width = 50; height = 17; x = 6; y = 73; text = " Unique"; col.sunique = this; } new GuiCheckBoxCtrl(name @ "_AutoInc") { profile = GuiBlueCheckBoxProfile; useownprofile = true; profile.fontColor = "0 0 0"; width = 100; height = 17; x = 63; y = 73; text = " Auto Increment"; col.sauto = this; } new GuiCheckBoxCtrl(name @ "_NotNull") { profile = GuiBlueCheckBoxProfile; useownprofile = true; profile.fontColor = "0 0 0"; width = 70; height = 17; x = 160; y = 73; text = " Not Null"; col.snotnull = this; } new GuiButtonCtrl(name @ "_Remove") { profile = GuiBlueButtonProfile; width = 40; height = 19; x = 220; y = 72; text = "x"; thiso.catchEvent(this, "onAction", "onRemoveColumn"); } par.cols.add(this); } this.colNum ++; this.scrollToBottom(); } } function onRemoveColumn(button) { temp.column = button.parent; with (SQLNewT_Columns) { temp.indx = this.cols.index(@ column); this.cols.remove(column); temp.dy = column.height; column.destroy(); for (temp.col = indx; col < this.cols.size(); col ++) { cols[col].profile.fillColor = col % 2 == 1 ? "199 219 226" : "153 184 202"; if (col < indx) { continue; } this.cols[col].y -= (dy - 1); } } } // Basic GUI stuff function msg(msg) { new GuiWindowCtrl("SQLMessage" @ (++ this.messageID) @ "_Window") { profile = GuiBlueWindowProfile; minExtent = "0 0"; width = 250; height = 140; x = GraalControl.width / 2 - (width / 2); y = (- 1000); // temp canClose = canMove = clientRelative = destroyOnClose = visible = true; isExternal = SQL_Window.isExternal; canMinimize = canMaximize = canResize = false; text = "Alert"; window = this; this.wType = 0; new GuiMLTextCtrl(name @ "_Text") { profile = GuiBlueMLTextProfile; x = 1; y = 3; width = 240; text = "<center>" @ msg @ "</center>"; thiso.catchEvent(this, "onReflow", "onMessageTextResized"); } new GuiButtonCtrl(name @ "_Close") { profile = GuiBlueButtonProfile; width = 232; height = 25; x = 3; y = 82; vertSizing = "top"; text = "Close"; thiso.catchEvent(this, "onAction", "onCloseWindow"); } } } function onMessageTextResized(text) { temp.window = text.parent; temp.nH = 45; if (window.wType == 1) { nH = 98; } else if (window.wType == 2) { nH = 70; } else if (window.wType == 3) { nH = 45; } window.height = text.height + nH; window.visible = true; window.showTop(); window.y = GraalControl.height / 2 - (window.height / 2); } function onCloseWindow(button) { button.parent.destroy(); } function msg2(msg, msg2) { new GuiWindowCtrl("SQLMessage" @ (++ this.messageID) @ "_Window") { profile = GuiBlueWindowProfile; minExtent = "0 0"; width = 250; height = 140; x = GraalControl.width / 2 - (width / 2); y = (- 1000); // temp canClose = canMove = clientRelative = destroyOnClose = visible = true; isExternal = SQL_Window.isExternal; canMinimize = canMaximize = canResize = false; destroyonclose = true; text = "Alert"; window = this; this.wType = 1; new GuiMLTextCtrl(name @ "_Text") { profile = GuiBlueMLTextProfile; x = 1; y = 3; width = 240; text = "<center>" @ msg @ "</center>"; thiso.catchEvent(this, "onReflow", "onMessageTextResized"); } new GuiScrollCtrl(name @ "_Scroll") { profile = GuiBlueScrollProfile; useownprofile = true; profile.border = 1; x = 3; y = 29; width = 232; height = 50; hScrollBar = "alwaysOff"; vertSizing = "top"; new GuiMLTextCtrl(name @ "_Text") { profile = GuiBlueMLTextProfile; width = 210; x = 1; y = 1; text = msg2; } } new GuiButtonCtrl(name @ "_Close") { profile = GuiBlueButtonProfile; width = 232; height = 25; x = 3; y = 82; vertSizing = "top"; text = "Close"; thiso.catchEvent(this, "onAction", "onCloseWindow"); } } } function ask(msg, button, func, par) { new GuiWindowCtrl("SQLMessage" @ (++ this.messageID) @ "_Window") { profile = GuiBlueWindowProfile; minExtent = "0 0"; width = 250; height = 140; x = GraalControl.width / 2 - (width / 2); y = (- 1000); // temp canClose = canMove = clientRelative = destroyOnClose = visible = true; isExternal = SQL_Window.isExternal; canMinimize = canMaximize = canResize = false; destroyonclose = true; text = "Question"; window = this; this.wType = 2; this.fun = func; this.pa = par; new GuiMLTextCtrl(name @ "_Text") { profile = GuiBlueMLTextProfile; x = 1; y = 3; width = 240; text = "<center>" @ msg @ "</center>"; thiso.catchEvent(this, "onReflow", "onMessageTextResized"); } new GuiTextEditCtrl(name @ "_TextEdit") { profile = GuiBlueTextEditProfile; width = 232; height = 20; x = 3; y = 59; text = ""; vertSizing = "top"; window.input = this; } new GuiButtonCtrl(name @ "_Submit") { profile = GuiBlueButtonProfile; width = 232; height = 25; x = 3; y = 82; vertSizing = "top"; text = button; thiso.catchEvent(this, "onAction", "onSubmitWindow"); } } } function onSubmitWindow(button) { temp.window = button.parent; temp.input = window.input.text; temp.func = window.fun; temp.par = window.pa; window.destroy(); this.(@ func)(par, input); } function ask2(msg, button1, button2, func, par) { new GuiWindowCtrl("SQLMessage" @ (++ this.messageID) @ "_Window") { profile = GuiBlueWindowProfile; minExtent = "0 0"; width = 250; height = 140; x = GraalControl.width / 2 - (width / 2); y = (- 1000); // temp canClose = canMove = clientRelative = visible = true; isExternal = SQL_Window.isExternal; canMinimize = canMaximize = canResize = false; destroyonclose = true; text = "Question"; window = this; this.wType = 3; this.fun = func; this.pa = par; new GuiMLTextCtrl(name @ "_Text") { profile = GuiBlueMLTextProfile; x = 1; y = 3; width = 240; text = "<center>" @ msg @ "</center>"; thiso.catchEvent(this, "onReflow", "onMessageTextResized"); } new GuiButtonCtrl(name @ "_Submit1") { profile = GuiBlueButtonProfile; width = 111; height = 25; x = 6; y = 82; vertSizing = "top"; text = button1; this.o = 0; thiso.catchEvent(this, "onAction", "onSubmitWindow2"); } new GuiButtonCtrl(name @ "_Submit2") { profile = GuiBlueButtonProfile; width = 111; height = 25; x = 121; y = 82; vertSizing = "top"; text = button2; this.o = 1; thiso.catchEvent(this, "onAction", "onSubmitWindow2"); } } } function onSubmitWindow2(button) { temp.input = button.o; temp.window = button.parent; temp.func = window.fun; temp.par = window.pa; window.destroy(); this.(@ func)(par, input); } // Serverside & Clientside Interaction function getServer(cmd, par) { triggerserver("gui", name, "get", cmd, par); } function tellServer(cmd, par) { triggerserver("gui", name, "tell", cmd, par); } function onActionClientSide(cmd, func, par) { switch (cmd) { case "return": getCommand(func, par); break; case "msg": msg(func); break; case "msg2": msg2(func, par); break; case "execute": if (func == "results") { executeResults(par[0], par[1]); } else if (func == "echo") { sqlEcho(par); } break; } }