`
luck332
  • 浏览: 86363 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

SQL在线查询设计器

阅读更多

 

//http://www.html580.com
Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLTableSprite', {
    extend: 'Ext.draw.Sprite',
    alias: ['widget.sqltablesprite'],
    bConnections: false,
    startDrag: function(id){
        var me = this, win, sqlTablePanel, xyParentPos, xyChildPos;
        
        // get a reference to a sqltable
        win = Ext.getCmp(id);
        
        // get the main sqlTablePanel
        sqlTablePanel = Ext.getCmp('SQLTablePanel');
        
        // get the main sqlTablePanel position
        xyParentPos = sqlTablePanel.el.getXY();
        
        // get the size of the previously added sqltable
        xyChildPos = win.el.getXY();
        
        me.prev = me.surface.transformToViewBox(xyChildPos[0] - xyParentPos[0] + 2, xyChildPos[1] - xyParentPos[1] + 2);
    },
    
    onDrag: function(relPosMovement){
        var xy, me = this, attr = this.attr, newX, newY;
        // move the sprite
        // calculate new x and y position
        newX = me.prev[0] + relPosMovement[0];
        newY = me.prev[1] + relPosMovement[1];
        // set new x and y position and redraw sprite
        me.setAttributes({
            x: newX,
            y: newY
        
        }, true);
    }
}); 

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLTableModel', {
    extend: 'Ext.data.Model',
    fields: [{
        name: 'id',
        type: 'string'
    }, {
        name: 'tableName',
        type: 'string'
    }, {
        name: 'tableAlias',
        type: 'string'
    }]
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLTableStore', {
    extend: 'Ext.data.Store',
    autoSync: true,
    model: 'Ext.ux.window.visualsqlquerybuilder.SQLTableModel',
    proxy: {
        type: 'memory'
    }
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLJoin', {
    extend: 'Ext.data.Model',
    fields: [{
        name: 'id',
        type: 'string'
    }, {
        name: 'leftTableId',
        type: 'string'
    }, {
        name: 'rightTableId',
        type: 'string'
    }, {
        name: 'leftTableField',
        type: 'string'
    }, {
        name: 'rightTableField',
        type: 'string'
    }, {
        name: 'joinCondition',
        type: 'string'
    }, {
        name: 'joinType',
        type: 'string'
    }],
    createUUID: function(){
        // http://www.ietf.org/rfc/rfc4122.txt
        var s = [];
        var hexDigits = "0123456789abcdef";
        for (var i = 0; i < 36; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23] = "-";
        
        var uuid = s.join("");
        return uuid;
    }
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.JoinStore', {
    extend: 'Ext.data.Store',
    autoSync: true,
    model: 'Ext.ux.window.visualsqlquerybuilder.SQLJoin',
    proxy: {
        type: 'memory'
    }
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLFieldsModel', {
    extend: 'Ext.data.Model',
    fields: [{
        name: 'id',
        type: 'string'
    }, {
        name: 'tableName',
        type: 'string'
    }, {
        name: 'tableId',
        type: 'string'
    }, {
        name: 'extCmpId',
        type: 'string'
    }, {
        name: 'tableAlias',
        type: 'string'
    }, {
        name: 'field',
        type: 'string'
    }, {
        name: 'output',
        type: 'boolean'
    }, {
        name: 'expression',
        type: 'string'
    }, {
        name: 'aggregate',
        type: 'string'
    }, {
        name: 'alias',
        type: 'string'
    }, {
        name: 'sortType',
        type: 'string'
    }, {
        name: 'sortOrder',
        type: 'int'
    }, {
        name: 'grouping',
        type: 'boolean'
    }, {
        name: 'criteria',
        type: 'string'
    }]
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLFieldsStore', {
    extend: 'Ext.data.Store',
    autoSync: true,
    model: 'Ext.ux.window.visualsqlquerybuilder.SQLFieldsModel',
    proxy: {
        type: 'memory'
    }
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLSelect', {
    config: {
        tables: '',
        fields: '',
        joins: ''
    },
    constructor: function(){
    
        this.tables = Ext.create('Ext.ux.window.visualsqlquerybuilder.SQLTableStore', {
            storeId: 'SQLTableStore'
        });
        
        // handle all updates on sql tables
        this.tables.on('update', this.handleSQLTableUpdate, this);
        this.tables.on('add', this.handleSQLTableAdd, this);
        this.tables.on('remove', this.handleSQLTableRemove, this);
        
        this.fields = Ext.create('Ext.ux.window.visualsqlquerybuilder.SQLFieldsStore', {
            storeId: 'SQLFieldsStore'
        });
        
        this.fields.on('update', this.handleSQLFieldChanges, this);
        this.fields.on('remove', this.handleSQLFieldRemove, this);
        
        this.joins = Ext.create('Ext.ux.window.visualsqlquerybuilder.JoinStore', {
            storeId: 'JoinStore'
        });
        
        // this.joins.on('update', this.handleSQLJoinChanges, this);
        this.joins.on('add', this.handleSQLJoinChanges, this);
        this.joins.on('remove', this.handleSQLJoinChanges, this);
        
        this.callParent(arguments);
    },
    handleSQLTableUpdate: function(tableStore, table, operation){
        if (operation == 'commit') {
            this.updateFieldTableData(table);
            this.updateJoinTableData(table);
            this.updateSQLOutput();
        }
    },
    handleSQLTableAdd: function(tableStore, table, index){
        this.updateSQLOutput();
    },
    handleSQLTableRemove: function(tableStore, table, index){
        var aJoins = [];
        // get table joins and remove them
        aJoins = this.getJoinsByTableId(table.get('id'));
        // loop over the joins array
        for (var i = 0, l = aJoins.length; i < l; i++) {
            // remove join from store
            this.removeJoinById(aJoins[i].get('id'));
        }
        this.updateSQLOutput();
    },
    handleSQLJoinChanges: function(joinStore, join){
        this.updateSQLOutput();
    },
    updateFieldTableData: function(table){
        var tableId, expression, tableAlias, tableName;
        tableId = table.get('id');
        tableAlias = table.get('tableAlias');
        tableName = table.get('tableName');
        // loop over all fields of the fields store
        this.fields.each(function(field){
            // check if current field belongs to sql table
            if (field.get('tableId') == tableId) {
                if (tableAlias != '') {
                    // we have a table alias
                    expression = tableAlias + '.' + field.get('field');
                }
                else {
                    // no table alias
                    expression = tableName + '.' + field.get('field');
                };
                field.beginEdit();
                // update the field table alias
                field.set('tableAlias', tableAlias);
                // update the field expression
                field.set('expression', expression);
                field.commit(true);
                field.endEdit();
            }
        });
        return;
    },
    updateJoinTableData: function(table){
        var joins, tableId;
        tableId = table.get('id');
        joins = this.getJoinsByTableId(tableId);
        for (var i = 0, rightTable, leftTable, joinCondition = '',l = joins.length; i < l; i++) {
            leftTable = this.getTableById(joins[i].get('leftTableId'));
            rightTable = this.getTableById(joins[i].get('rightTableId'));
            
            if (leftTable.get('tableAlias') != '') {
                joinCondition = joinCondition + leftTable.get('tableAlias') + '.' + joins[i].get('leftTableField') + '=';
            }
            else {
                joinCondition = joinCondition + leftTable.get('tableName') + '.' + joins[i].get('leftTableField') + '=';
            }
            
            if (rightTable.get('tableAlias') != '') {
                joinCondition = joinCondition + rightTable.get('tableAlias') + '.' + joins[i].get('rightTableField');
            }
            else {
                joinCondition = joinCondition + rightTable.get('tableName') + '.' + joins[i].get('rightTableField');
            }
            joins[i].beginEdit();
            joins[i].set('joinCondition', joinCondition);
            joins[i].commit(true);
            joins[i].endEdit();
        }
    },
    handleSQLFieldChanges: function(fieldStore, model, operation){
        if (operation == 'commit') {
            this.updateSQLOutput();
        }
    },
    handleSQLFieldRemove: function(fieldStore){
        this.updateSQLOutput();
    },
    updateSQLOutput: function(){
        var sqlOutput, sqlHTML, sqlQutputPanel;
        sqlOutput = this.toString();
        sqlHTML = '<pre class="brush: sql">' + sqlOutput + '</pre>';
        sqlQutputPanel = Ext.getCmp('SQLOutputPanel');
        
        sqlQutputPanel.update(sqlHTML);
    },
    sortTablesByJoins: function(tables, oUsedTables){
        var aTables = [], aJoins = [], oUsedTables = oUsedTables ||
        {};
        // loop over tables
        for (var i = 0, aCondition = [], aJoin, l = tables.length; i < l; i++) {
            // check if current table is a new one
            if (!oUsedTables.hasOwnProperty(tables[i].get('id'))) {
                // it is a new one
                aTables.push(tables[i]);
                // mark table as used
                oUsedTables[tables[i].get('id')] = true;
                // get any joins for the current table
                aJoin = this.getJoinsByTableId(tables[i].get('id'));
                // loop over the join tables
                for (var j = 0, joinTable, len = aJoin.length; j < len; j++) {
                    // check if it is a new join
                    if (!oUsedTables.hasOwnProperty(aJoin[j].get('id'))) {
                        // mark join as used
                        oUsedTables[aJoin[j].get('id')] = true;
                        if (tables[i].get('id') != aJoin[j].get('leftTableId')) {
                            joinTable = this.getTableById(aJoin[j].get('leftTableId'));
                            this.changeLeftRightOnJoin(aJoin[j]);
                        }
                        else {
                            joinTable = this.getTableById(aJoin[j].get('rightTableId'));
                        }
                        oTemp = this.sortTablesByJoins([joinTable], oUsedTables);
                        oUsedTables = oTemp.oUsedTables;
                        aTables = aTables.concat(oTemp.aTables);
                    }
                }
            }
        }
        
        return {
            aTables: aTables,
            oUsedTables: oUsedTables
        };
    },
    changeLeftRightOnJoin: function(join){
        var leftTable, leftTableField, rightTable, rightTableField, joinCondition = '';
        // prepare new data
        leftTable = this.getTableById(join.get('rightTableId'));
        leftTableField = join.get('rightTableField');
        rightTable = this.getTableById(join.get('leftTableId'));
        rightTableField = join.get('leftTableField');
        
        // construct new joinCondition
        if (leftTable.get('tableAlias') != '') {
            joinCondition = joinCondition + leftTable.get('tableAlias') + '.' + join.get('rightTableField') + '=';
        }
        else {
            joinCondition = joinCondition + leftTable.get('tableName') + '.' + join.get('rightTableField') + '=';
        }
        
        if (rightTable.get('tableAlias') != '') {
            joinCondition = joinCondition + rightTable.get('tableAlias') + '.' + join.get('leftTableField');
        }
        else {
            joinCondition = joinCondition + rightTable.get('tableName') + '.' + join.get('leftTableField');
        }
        
        // start transaction
        join.beginEdit();
        // change left and right join table data
        join.set('leftTableId', leftTable.get('id'));
        join.set('leftTableField', leftTableField);
        join.set('rightTableId', rightTable.get('id'));
        join.set('rightTableField', rightTableField);
        join.set('joinCondition', joinCondition);
        // silent commit without firing store events
        // this prevents endless loop
        join.commit(true);
        join.endEdit();
        // end transaction
        return;
    },
    toString: function(){
        var sqlOutput = 'SELECT ', aJoins = [], aOutputFields = [], oJoinTables = {}, aTables = [], aJoinTables = [], aCriteriaFields = [], aGroupFields = [], aOrderFields = [], selectFieldsSQL = '', fromSQL = '', aFromSQL = [], criteriaSQL = '', orderBySQL = '', groupBySQL = '', fieldSeperator = ', ', joinSQL = '', bFirst = true, bPartOfJoin = false;
        this.fields.each(function(field){
            // should the field be a part of the output
            if (field.get('output')) {
                aOutputFields.push(field);
            }
            // any criteria
            if (field.get('criteria') != '') {
                aCriteriaFields.push(field);
            }
            // check for grouping
            if (field.get('grouping')) {
                aGroupFields.push(field);
            }
            // check for sorting
            if (field.get('sortType') != '') {
                aOrderFields.push(field);
            }
        });
        
        // tables
        // sorting of tables
        this.tables.each(function(table){
            aTables.push(table);
        });
        
        aTables = this.sortTablesByJoins(aTables).aTables;
        
        
        this.joins.each(function(join){
            aJoins.push(join);
        });
        
        //create fromSQL
        for (var k = 0, aJoin = [], oJoinTables = {}, joinCondition = '', joinType, leftTable, rightTable, l = aTables.length; k < l; k++) {
            if (k == aTables.length - 1) {
                fieldSeperator = '';
            }
            else {
                fieldSeperator = ', ';
            };
            
            // is the current table the first one
            if (bFirst) {
                // yes it is the first
                
                // table id merken
                oJoinTables[aTables[k].get('id')] = true;
                
                bFirst = false;
                
                // check if current table is not the last one in the loop 
                if ((k + 1) < aTables.length) {
                    // get joins where joins leftTableID is a property of oJoinTables and joins rightTableID equal to aTables[i+1].get('id')
                    for (var h = 0, len = aJoins.length; h < len; h++) {
                        if (oJoinTables.hasOwnProperty(aJoins[h].get('leftTableId')) && aJoins[h].get('rightTableId') == aTables[k + 1].get('id')) {
                            aJoin.push(aJoins[h]);
                        }
                        if (oJoinTables.hasOwnProperty(aJoins[h].get('rightTableId')) && aJoins[h].get('leftTableId') == aTables[k + 1].get('id')) {
                            this.changeLeftRightOnJoin(aJoins[h]);
                            aJoin.push(aJoins[h]);
                        }
                    }
                    
                    // check if we have a join
                    if (aJoin.length > 0) {
                        // yes we have a join between aTables[k] and aTables[k+1] with at least one join condition
                        
                        leftTable = aTables[k];
                        rightTable = aTables[k + 1];
                        
                        // table id merken
                        oJoinTables[rightTable.get('id')] = true;
                        
                        for (var j = 0, fieldSeperator = '', ln = aJoin.length; j < ln; j++) {
                            if (j == aJoin.length - 1) {
                                fieldSeperator = '';
                            }
                            else {
                                fieldSeperator = '\nAND ';
                            };
                            joinType = aJoin[j].get('joinType');
                            joinCondition = joinCondition + aJoin[j].get('joinCondition') + fieldSeperator;
                        }
                        
                        // reset the join array 
                        aJoin = [];
                        
                        if (joinSQL != '') {
                            joinSQL = joinSQL + ',\n';
                        }
                        
                        if (leftTable.get('tableAlias') != '') {
                            // we have an leftTable alias
                            joinSQL = joinSQL + leftTable.get('tableName') + ' ' + leftTable.get('tableAlias') + ' ' + joinType + ' JOIN ';
                        }
                        else {
                            //no alias
                            joinSQL = joinSQL + leftTable.get('tableName') + ' ' + joinType + ' JOIN ';
                        }
                        
                        if (rightTable.get('tableAlias') != '') {
                            // we have an rightTable alias
                            joinSQL = joinSQL + rightTable.get('tableName') + ' ' + rightTable.get('tableAlias') + ' ON ' + joinCondition;
                        }
                        else {
                            //no alias
                            joinSQL = joinSQL + rightTable.get('tableName') + ' ON ' + joinCondition;
                        }
                        
                        // clear joinCondition
                        joinCondition = '';
                        
                    }
                    else {
                        // no join between aTables[i+1] and the one before
                        bFirst = true;
                        oJoinTables = {};
                        // check for tableAlias
                        if (aTables[k].get('tableAlias') != '') {
                            fromSQL = aTables[k].get('tableName') + ' ' + aTables[k].get('tableAlias');
                        }
                        else {
                            fromSQL = aTables[k].get('tableName');
                        }
                        aFromSQL.push(fromSQL);
                    }
                }
                else {
                    // its the last and only one in the loop
                    // check for tableAlias
                    if (aTables[k].get('tableAlias') != '') {
                        fromSQL = aTables[k].get('tableName') + ' ' + aTables[k].get('tableAlias');
                    }
                    else {
                        fromSQL = aTables[k].get('tableName');
                    }
                    aFromSQL.push(fromSQL);
                }
            }
            else {
                // no, it is not the first table
                
                bFirst = true;
                
                // check if current table is not the last one in the loop 
                if ((k + 1) < aTables.length) {
                    // get joins where joins leftTableID is a property of oJoinTables and joins rightTableID equal to aTables[i+1].get('id')
                    for (var h = 0, len = aJoins.length; h < len; h++) {
                        if (oJoinTables.hasOwnProperty(aJoins[h].get('leftTableId')) && aJoins[h].get('rightTableId') == aTables[k + 1].get('id')) {
                            aJoin.push(aJoins[h]);
                        }
                        if (oJoinTables.hasOwnProperty(aJoins[h].get('rightTableId')) && aJoins[h].get('leftTableId') == aTables[k + 1].get('id')) {
                            this.changeLeftRightOnJoin(aJoins[h]);
                            aJoin.push(aJoins[h]);
                        }
                    }
                    
                    // check if we have a join
                    if (aJoin.length > 0) {
                        // yes we have a join between aTables[k] and aTables[k+1] with at least one join condition
                        
                        rightTable = aTables[k + 1];
                        
                        // table id merken
                        oJoinTables[rightTable.get('id')] = true;
                        
                        for (var j = 0, fieldSeperator = '', ln = aJoin.length; j < ln; j++) {
                            if (j == aJoin.length - 1) {
                                fieldSeperator = '';
                            }
                            else {
                                fieldSeperator = '\nAND ';
                            };
                            joinType = aJoin[j].get('joinType');
                            joinCondition = joinCondition + aJoin[j].get('joinCondition') + fieldSeperator;
                        }
                        
                        // reset the join array 
                        aJoin = [];
                        
                        bFirst = false;
                        
                        if (rightTable.get('tableAlias') != '') {
                            // we have an rightTable alias
                            joinSQL = joinSQL + '\n' + joinType + ' JOIN ' + rightTable.get('tableName') + ' ' + rightTable.get('tableAlias') + ' ON ' + joinCondition;
                        }
                        else {
                            //no alias
                            joinSQL = joinSQL + '\n' + joinType + ' JOIN ' + rightTable.get('tableName') + ' ON ' + joinCondition;
                        }
                        
                        // clear joinCondition
                        joinCondition = '';
                    }
                    else {
                        bFirst = true;
                        oJoinTables = {};
                    }
                }
                else {
                    // its the last and only one
                    // check for tableAlias
                    oJoinTables = {};
                }
            }
        }
        
        fromSQL = aFromSQL.join(', ');
        
        if (joinSQL != '' && fromSQL != '') {
            joinSQL = joinSQL + ', ';
        }
        
        fromSQL = '\nFROM ' + joinSQL + fromSQL;
        
        // output fields
        for (var i = 0, l = aOutputFields.length; i < l; i++) {
            // check if it is the last array member
            if (i == aOutputFields.length - 1) {
                fieldSeperator = '';
            }
            else {
                fieldSeperator = ', ';
            };
            // yes, output
            // check alias
            if (aOutputFields[i].get('alias') != '') {
                // yes, we have an field alias
                selectFieldsSQL = selectFieldsSQL + aOutputFields[i].get('expression') + ' AS ' + aOutputFields[i].get('alias') + fieldSeperator;
            }
            else {
                // no field alias
                selectFieldsSQL = selectFieldsSQL + aOutputFields[i].get('expression') + fieldSeperator;
            }
        }
        
        // criteria
        for (var i = 0, l = aCriteriaFields.length; i < l; i++) {
            if (i == 0) {
                criteriaSQL = criteriaSQL + '\nWHERE ';
            }
            else {
                criteriaSQL = criteriaSQL + 'AND ';
            }
            if (i == aCriteriaFields.length - 1) {
                fieldSeperator = '';
            }
            else {
                fieldSeperator = '\n';
            }
            criteriaSQL = criteriaSQL + aCriteriaFields[i].get('expression') + ' ' + aCriteriaFields[i].get('criteria') + fieldSeperator;
        }
        
        // group by
        for (var i = 0, l = aGroupFields.length; i < l; i++) {
            // check if it is the last array member
            if (i == aGroupFields.length - 1) {
                fieldSeperator = '';
            }
            else {
                fieldSeperator = ', ';
            }
            if (i == 0) {
                groupBySQL = '\nGROUP BY ';
            }
            groupBySQL = groupBySQL + aGroupFields[i].get('expression') + fieldSeperator;
        }
        
        // order by
        for (var i = 0, l = aOrderFields.length; i < l; i++) {
            // check if it is the last array member
            if (i == aOrderFields.length - 1) {
                fieldSeperator = '';
            }
            else {
                fieldSeperator = ', ';
            }
        }
        
        return sqlOutput + selectFieldsSQL + fromSQL + criteriaSQL + groupBySQL + orderBySQL;
    },
    getJoinsByTableId: function(tableId){
        var aReturn = [];
        this.joins.each(function(join){
            if (join.get('leftTableId') == tableId || join.get('rightTableId') == tableId) {
                aReturn.push(join);
            }
        });
        return aReturn;
    },
    removeTableById: function(tableID){
        var table;
        table = this.tables.getById(tableID);
        this.tables.remove(table);
    },
    getTableById: function(tableID){
        return this.tables.getById(tableID);
    },
    removeFieldById: function(id){
        var field;
        field = this.fields.getById(id);
        this.fields.remove(field);
    },
    removeFieldsByTableId: function(tableId){
        var aRecords = [];
        this.fields.each(function(model){
            if (model.get('tableId') == tableId) {
                aRecords.push(model);
            }
        });
        this.fields.remove(aRecords);
    },
    addTable: function(table){
        this.tables.add(table);
    },
    addFieldRecord: function(record, bOutput){
        var tableAlias, model, expression;
        // get the tableAlias
        tableAlias = this.getTableById(record.get('tableId')).get('tableAlias');
        // build the expression
        // check if the tableAlias is not an empty string
        if (tableAlias != '') {
            // alias is not an empty string
            expression = tableAlias + '.' + record.get('field');
        }
        else {
            // alias is an empty string
            expression = record.get('tableName') + '.' + record.get('field');
        };
        // get a new field instance
        model = this.getNewField();
        // set the expression
        model.set('expression', expression);
        // set output to false per default
        model.set('output', bOutput);
        // set an id, so it is possible to remove rows if the associated table is removed
        model.set('id', record.get('id'));
        // set the field
        model.set('field', record.get('field'));
        // copy tableId to the new model instance
        model.set('tableId', record.get('tableId'));
        // copy cmp id of origin sqltable to the new model instance
        model.set('extCmpId', record.get('extCmpId'));
        this.addField(model);
    },
    addField: function(field){
        this.fields.add(field);
    },
    getNewField: function(){
        return Ext.create('Ext.ux.window.visualsqlquerybuilder.SQLFieldsModel');
    },
    removeJoinById: function(joinID){
        var join;
        join = this.joins.getById(joinID);
        this.joins.remove(join);
    },
    addJoin: function(join){
        this.joins.add(join);
    },
    arrayRemove: function(array, filterProperty, filterValue){
        var aReturn;
        aReturn = Ext.Array.filter(array, function(item){
            var bRemove = true;
            if (item[filterProperty] == filtervalue) {
                bRemove = false;
            }
            return bRemove;
        });
        return aReturn
    }
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLTablePanel', {
    extend: 'Ext.panel.Panel',
    alias: ['widget.sqltablepanel'],
    id: 'SQLTablePanel',
    items: [{
        xtype: 'draw',
        listeners: {
            afterrender: function(){
                this.initDropTarget();
            }
        },
        initDropTarget: function(){
            // init draw component inside qbwindow as a DropTarget
            this.dropTarget = Ext.create('Ext.dd.DropTarget', this.el, {
                ddGroup: 'sqlDDGroup',
                notifyDrop: function(source, event, data){
                    var sqlTablePanel;
                    // add a sqltable to the sqlTablePanel component
                    sqlTablePanel = Ext.getCmp('SQLTablePanel');
                    sqlTablePanel.add({
                        xtype: 'sqltable',
                        constrain: true,
                        title: data.records[0].get('text')
                    }).show();
                    return true;
                }
            });
        }
    }]
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLOutputPanel', {
    extend: 'Ext.panel.Panel',
    alias: ['widget.sqloutputpanel'],
    id: 'SQLOutputPanel',
    listeners: {
        afterlayout: function(){
            SyntaxHighlighter.highlight();
        }
    },
    initComponent: function(){
        this.callParent(arguments);
    }
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLFieldsGrid', {
	requires: ['Ext.ux.CheckColumn'],
    extend: 'Ext.grid.Panel',
    alias: ['widget.sqlfieldsgrid'],
    id: 'SQLFieldsGrid',
    store: 'SQLFieldsStore',
    columnLines: true,
    plugins: [Ext.create('Ext.grid.plugin.CellEditing', {
        clicksToEdit: 1
    })],
    viewConfig: {
        listeners: {
            render: function(view){
                this.dd = {};
                this.dd.dropZone = new Ext.grid.ViewDropZone({
                    view: view,
                    ddGroup: 'SQLTableGridDDGroup',
                    handleNodeDrop: function(data, record, position){
                        // Was soll nach dem Drop passieren?
                    }
                });
            },
            drop: function(node, data, dropRec, dropPosition){
                // add new rows to the SQLFieldsGrid after a drop
                for (var i = 0, l = data.records.length; i < l; i++) {
                    ux.vqbuilder.sqlSelect.addFieldRecord(data.records[i], false);
                }
            }
        }
    },
    columns: [{
        xtype: 'actioncolumn',
		menuDisabled: true,
        text: 'Action',
        width: 60,
        moveGridRow: function(grid, record, index, direction){
            var store = grid.getStore();
            if (direction < 0) {
                index--;
                if (index < 0) {
                    return;
                }
            }
            else {
                index++;
                if (index >= grid.getStore().getCount()) {
                    return;
                }
            }
            // prepare manual syncing
            store.suspendAutoSync();
            // disable firing store events
            store.suspendEvents();
            // remove record and insert record at new index
            store.remove(record);
            store.insert(index, record);
            // enable firing store events
            store.resumeEvents();
            store.resumeAutoSync();
            // manual sync the store
            store.sync();
        },
        items: [{
            icon: 'resources/images/up_arrow.gif',
            tooltip: 'Move Column Up',
            getClass: function(value, metadata, record){
                var store, index;
                store = record.store;
                index = store.indexOf(record);
                if (index == 0) {
                    return 'x-action-icon-disabled';
                }
                else {
                    return 'x-grid-center-icon';
                }
            },
            handler: function(grid, rowIndex, colIndex){
                var rec = grid.getStore().getAt(rowIndex);
                this.moveGridRow(grid, rec, rowIndex, -1);
            }
        }, {
            icon: 'resources/images/down_arrow.gif',
            getClass: function(value, metadata, record){
                var store, index;
                store = record.store;
                index = store.indexOf(record);
                if ((index + 1) == store.getCount()) {
                    return 'x-action-icon-disabled';
                }
                else {
                    return 'x-grid-center-icon';
                }
            },
            tooltip: 'Move Column Down',
            handler: function(grid, rowIndex, colIndex){
                var rec = grid.getStore().getAt(rowIndex);
                this.moveGridRow(grid, rec, rowIndex, 1);
            }
        }, {
            icon: 'resources/images/remove.gif',
            iconCls: 'x-grid-center-icon',
            tooltip: 'Delete Column',
            handler: function(grid, rowIndex, colIndex){
                var rec = grid.getStore().getAt(rowIndex), store, tableId, tableGrid, selectionModel, bDel = true;
                // rec contains column grid model, the one to remove
                // get tableId of original sqltable
                tableId = rec.get('extCmpId');
                // get the sql tables grid and its selection
                tableGrid = Ext.getCmp(tableId).down('gridpanel');
                selectionModel = tableGrid.getSelectionModel();
                Ext.Array.each(selectionModel.getSelection(), function(selection){
                    // deselect the selection wich corresponds to the column 
                    // we want to remove from the column grid
                    if (rec.get('id') == selection.get('id')) {
                        // deselect current selection
                        // deselection will lead to removal, look for method deselect at the SQLTableGrid
                        selectionModel.deselect(selection);
                        bDel = false;
                    }
                });
                if (bDel) {
                    store = grid.getStore();
                    store.remove(rec);
                }
            }
        }]
    }, {
        xtype: 'checkcolumn',
		sortable: false,
        text: 'Output',
        flex: 0.075,
        menuDisabled: true,
        dataIndex: 'output',
		align: 'center'
    }, {
        xtype: 'gridcolumn',
        text: 'Expression',
		sortable: false,
		menuDisabled: true,
        flex: 0.225,
        dataIndex: 'expression',
        editor: 'textfield'
    }, {
        xtype: 'gridcolumn',
        text: 'Aggregate',
        flex: 0.125,
		sortable: false,
        menuDisabled: true,
        dataIndex: 'aggregate',
        editor: 'textfield'
    }, {
        xtype: 'gridcolumn',
        text: 'Alias',
        flex: 0.125,
		sortable: false,
        menuDisabled: true,
        dataIndex: 'alias',
        editor: 'textfield'
    }, {
        xtype: 'gridcolumn',
        text: 'Sort Type',
        flex: 0.125,
		sortable: false,
        menuDisabled: true,
        dataIndex: 'sorttype'
    }, {
        xtype: 'gridcolumn',
        text: 'Sort Order',
        flex: 0.125,
		sortable: false,
        menuDisabled: true,
        dataIndex: 'sortorder'
    }, {
        xtype: 'checkcolumn',
        text: 'Grouping',
        flex: 0.075,
		sortable: false,
        menuDisabled: true,
        dataIndex: 'grouping',
		align: 'center'
    }, {
        xtype: 'gridcolumn',
        text: 'Criteria',
        flex: 0.125,
		sortable: false,
        menuDisabled: true,
        dataIndex: 'criteria',
        editor: 'textfield'
    }],
    initComponent: function(){
        this.callParent(arguments);
    }
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLTableTree', {
    extend: 'Ext.tree.Panel',
    alias: ['widget.sqltabletree'],
    id: 'SQLTableTree',
    listeners: {
        afterrender: function(){
            this.initTreeDragZone();
        },
        itemdblclick: function(view, record, el, index, event){
            var sqlTablePanel;
            // add a sqltable to the sqlTablePanel component
            sqlTablePanel = Ext.getCmp('SQLTablePanel');
            sqlTablePanel.add({
                xtype: 'sqltable',
                constrain: true,
                title: record.get('text')
            }).show();
            
        }
    },
    initTreeDragZone: function(){
        // init tree view as a ViewDragZone
        this.view.dragZone = new Ext.tree.ViewDragZone({
            view: this.view,
            ddGroup: 'sqlDDGroup',
            dragText: '{0} ausgew盲hlte Tabelle{1}',
            repairHighlightColor: 'c3daf9',
            repairHighlight: Ext.enableFx
        });
    },
    initComponent: function(){
    
        this.store = Ext.create('Ext.data.TreeStore', {
            root: {
                text: 'Tables',
                expanded: true
            },
            proxy: {
                type: 'ajax',
                url: 'data/database.cfc?method=getTables'
            }
        });
        
        this.callParent(arguments);
    }
});


Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLTableGrid', {
    extend: 'Ext.grid.Panel',
    alias: ['widget.sqltablegrid'],
    border: false,
    hideHeaders: true,
    viewConfig: {
        listeners: {
            bodyscroll: function(){
                var scrollOffset, sqlTable;
                // the bodyscroll event of the view was fired
                // get scroll information
                scrollOffset = this.el.getScroll();
                // get the parent sqltable
                sqlTable = this.up('sqltable');
                // change shadowSprites scrollTop property
                sqlTable.shadowSprite.scrollTop = scrollOffset.top;
                // redraw all connections to reflect scroll action
                for (var i = ux.vqbuilder.connections.length; i--;) {
                    sqlTable.connection(ux.vqbuilder.connections[i]);
                }
            },
            render: function(view){
                this.dd = {};
                // init the view as a DragZone
                this.dd.dragZone = new Ext.view.DragZone({
                    view: view,
                    ddGroup: 'SQLTableGridDDGroup',
                    dragText: '{0} selected table column{1}',
                    onInitDrag: function(x, y){
                        var me = this, data = me.dragData, view = data.view, selectionModel = view.getSelectionModel(), record = view.getRecord(data.item), e = data.event;
                        data.records = [record];
                        me.ddel.update(me.getDragText());
                        me.proxy.update(me.ddel.dom);
                        me.onStartDrag(x, y);
                        return true;
                    }
                });
                // init the view as a DropZone
                this.dd.dropZone = new Ext.grid.ViewDropZone({
                    view: view,
                    ddGroup: 'SQLTableGridDDGroup',
                    handleNodeDrop: function(data, record, position){
                        // Was soll nach dem Drop passieren?
                    },
                    onNodeOver: function(node, dragZone, e, data){
                        var me = this, view = me.view, pos = me.getPosition(e, node), overRecord = view.getRecord(node), draggingRecords = data.records;
                        
                        if (!Ext.Array.contains(data.records, me.view.getRecord(node))) {
                            if (!Ext.Array.contains(draggingRecords, overRecord) && data.records[0].get('field') != '*') {
                                me.valid = true;
                                // valid drop target
                                // todo show drop invitation
                            }
                            else {
                                // invalid drop target
                                me.valid = false;
                            }
                        }
                        return me.valid ? me.dropAllowed : me.dropNotAllowed;
                    },
                    onContainerOver: function(dd, e, data){
                        var me = this;
                        // invalid drop target
                        me.valid = false;
                        return me.dropNotAllowed;
                    }
                });
            },
            drop: function(node, data, dropRec, dropPosition){
                var sqlTable1, sqlTable2, showJoinCM, connection, aBBPos, join, joinCondition = '', dropTable, targetTable;
                
                showJoinCM = function(event, el){
                    var cm;
                    // stop the browsers event bubbling
                    event.stopEvent();
                    // create context menu
                    cm = Ext.create('Ext.menu.Menu', {
                        items: [{
                            text: 'Edit Join',
                            icon: 'resources/images/document_edit16x16.gif',
                            handler: Ext.Function.bind(function(){
                            
                            }, this)
                        }, {
                            text: 'Remove Join',
                            icon: 'resources/images/remove.gif',
                            handler: Ext.Function.bind(function(){
                                // remove any connection lines from surface and from array ux.vqbuilder.connections
                                ux.vqbuilder.connections = Ext.Array.filter(ux.vqbuilder.connections, function(connection){
                                    var bRemove = true;
                                    if (this.uuid == connection.uuid) {
                                        this.line.remove();
                                        this.bgLine.remove();
                                        this.miniLine1.remove();
                                        this.miniLine2.remove();
                                        bRemove = false;
                                    }
                                    return bRemove;
                                }, this);
                                ux.vqbuilder.sqlSelect.removeJoinById(this.uuid);
                            }, this)
                        }, {
                            text: 'Close Menu',
                            icon: 'resources/images/cross.gif',
                            handler: Ext.emptyFn
                        }]
                    });
                    // show the contextmenu next to current mouse position
                    cm.showAt(event.getXY());
                };
                
                if (node.boundView) {
                    sqlTable1 = data.view.up('window');
                    sqlTable1.shadowSprite.bConnections = true;
                    
                    sqlTable2 = Ext.getCmp(node.boundView).up('window');
                    sqlTable2.shadowSprite.bConnections = true;
                    
                    dropTable = ux.vqbuilder.sqlSelect.getTableById(sqlTable1.tableId);
                    targetTable = ux.vqbuilder.sqlSelect.getTableById(sqlTable2.tableId);
                    
                    aBBPos = [data.item.viewIndex, node.viewIndex];
                    
                    connection = sqlTable2.connection(sqlTable1.shadowSprite, sqlTable2.shadowSprite, "#000", aBBPos);
                    
                    sqlTable1.connectionUUIDs.push(connection.uuid);
                    sqlTable2.connectionUUIDs.push(connection.uuid);
                    
                    ux.vqbuilder.connections.push(connection);
                    
                    // bgLine is white(invisble) and its stroke-width is 10
                    // so it is easier to capture the dblclick event
                    connection.bgLine.el.on('contextmenu', showJoinCM, connection);
                    
                    // line is black and its stroke-width is 1
                    connection.line.el.on('contextmenu', showJoinCM, connection);
                    
                    // create an instance of the join model
                    join = Ext.create('Ext.ux.window.visualsqlquerybuilder.SQLJoin');
                    // set join id
                    join.set('id', connection.uuid);
                    // sqlTable1 is the left table
                    join.set('leftTableId', sqlTable1.tableId);
                    // data.records[0] represents the model of the dragged node
                    join.set('leftTableField', data.records[0].get('field'));
                    // sqlTable1 is the left table
                    join.set('rightTableId', sqlTable2.tableId);
                    // node.viewIndex is the index of the target node
                    join.set('rightTableField', sqlTable2.down('grid').store.getAt(node.viewIndex).get('field'));
                    // set the defaul join type to INNER
                    join.set('joinType', 'INNER');
                    
                    if (dropTable.get('tableAlias') != '') {
                        joinCondition = joinCondition + dropTable.get('tableAlias') + '.' + join.get('leftTableField') + '=';
                    }
                    else {
                        joinCondition = joinCondition + dropTable.get('tableName') + '.' + join.get('leftTableField') + '=';
                    }
                    
                    if (targetTable.get('tableAlias') != '') {
                        joinCondition = joinCondition + targetTable.get('tableAlias') + '.' + join.get('rightTableField');
                    }
                    else {
                        joinCondition = joinCondition + targetTable.get('tableName') + '.' + join.get('rightTableField');
                    }
                    
                    join.set('joinCondition', joinCondition);
                    ux.vqbuilder.sqlSelect.addJoin(join);
                }
                
            }
        }
    },
    initComponent: function(){
    
        this.columns = [{
            xtype: 'gridcolumn',
            width: 16,
            dataIndex: 'key',
            renderer: function(val, meta, model){
                if (val == 'PRI') {
                    meta.style = 'background-image:url(resources/images/key.gif) !important;background-position:2px 3px;background-repeat:no-repeat;';
                }
                return '';
            }
        }, {
            xtype: 'gridcolumn',
            flex: 1,
            dataIndex: 'field',
            renderer: function(val, meta, model){
                if (model.get('key') == 'PRI') {
                    return '<span style="font-weight: bold;">' + val + '</span><span style="color:#aaa;">' + model.get('type') + '</span>';
                }
                return val + '<span style="color:#999;">' + model.get('type') + '</span>';
                
            }
        }];
        
        this.selModel = Ext.create('Ext.selection.CheckboxModel', {
            mode: 'SIMPLE',
            checkOnly: true,
            listeners: {
                select: function(selModel, data){
                    // add new rows to the SQLFieldsGrid after a selection change
                    ux.vqbuilder.sqlSelect.addFieldRecord(data, true);
                },
                deselect: function(selModel, data){
                    var store, model;
                    // remove row from SQLFieldsGrid after deselection
                    ux.vqbuilder.sqlSelect.removeFieldById(data.get('id'));
                }
            }
        });
        
        this.callParent(arguments);
    }
});

Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLTable', {
    extend: 'Ext.window.Window',
    minWidth: 120,
    alias: ['widget.sqltable'],
    cascadeOnFirstShow: 20,
    height: 180,
    width: 140,
    shadowSprite: {},
    layout: {
        type: 'fit'
    },
    closable: true,
    listeners: {
        show: function(){
            this.initSQLTable();
        },
        beforeclose: function(){
            this.closeSQLTable();
        }
    },
    closeSQLTable: function(){
        // remove fields / columns from sqlFieldsStore
        ux.vqbuilder.sqlSelect.removeFieldsByTableId(this.tableId);
        
        // remove table from sqlTables store inside ux.vqbuilder.sqlSelect
        ux.vqbuilder.sqlSelect.removeTableById(this.tableId);
        
        // unregister mousedown event
        this.getHeader().el.un('mousedown', this.regStartDrag, this);
        // unregister mousemove event
        Ext.EventManager.un(document, 'mousemove', this.moveWindow, this);
        // remove sprite from surface
        Ext.getCmp('SQLTablePanel').down('draw').surface.remove(this.shadowSprite, false);
        // remove any connection lines from surface and from array ux.vqbuilder.connections
        ux.vqbuilder.connections = Ext.Array.filter(ux.vqbuilder.connections, function(connection){
            var bRemove = true;
            for (var j = 0, l = this.connectionUUIDs.length; j < l; j++) {
                if (connection.uuid == this.connectionUUIDs[j]) {
                    connection.line.remove();
                    connection.bgLine.remove();
                    connection.miniLine1.remove();
                    connection.miniLine2.remove();
                    bRemove = false;
                }
            }
            return bRemove;
        }, this);
        
    },
    initSQLTable: function(){
        var sqlTablePanel, xyParentPos, xyChildPos, childSize, sprite;
        
        // get the main sqlTablePanel
        sqlTablePanel = Ext.getCmp('SQLTablePanel');
        
        // get the main sqlTablePanel position
        xyParentPos = sqlTablePanel.el.getXY();
        
        // get position of the previously added sqltable
        xyChildPos = this.el.getXY();
        
        // get the size of the previously added sqltable
        childSize = this.el.getSize();
        
        // create a sprite of type rectangle and set its position and size 
        // to position and size of the the sqltable 
        sprite = Ext.create('Ext.ux.window.visualsqlquerybuilder.SQLTableSprite', {
            type: 'rect',
            stroke: '#fff',
            height: childSize.height - 4,
            width: childSize.width - 4,
            x: xyChildPos[0] - xyParentPos[0] + 2,
            y: xyChildPos[1] - xyParentPos[1] + 2,
            scrollTop: 0
        });
        
        // add the sprite to the surface of the sqlTablePanel
        this.shadowSprite = sqlTablePanel.down('draw').surface.add(sprite).show(true);
        
        // handle resizeing of sqltabel
        this.resizer.on('resize', function(resizer, width, height, event){
            this.shadowSprite.setAttributes({
                width: width - 6,
                height: height - 6
            }, true);
            // also move the associated connections 
            for (var i = ux.vqbuilder.connections.length; i--;) {
                this.connection(ux.vqbuilder.connections[i]);
            }
        }, this);
        
        // register a function for the mousedown event on the previously added sqltable and bind to this scope
        this.getHeader().el.on('mousedown', this.regStartDrag, this);
        
        this.getHeader().el.on('contextmenu', this.showSQLTableCM, this);
        
        this.getHeader().el.on('dblclick', this.showTableAliasEditForm, this);
        
        this.getHeader().origValue = '';
        
        // register method this.moveWindow for the mousemove event on the document and bind to this scope
        Ext.EventManager.on(document, 'mousemove', this.moveWindow, this);
        
        // register a function for the mouseup event on the document and add the this scope
        Ext.EventManager.on(document, 'mouseup', function(){
            // save the mousedown state
            this.bMouseDown = false;
        }, this);
        
        
    },
    showSQLTableCM: function(event, el){
        var cm;
        // stop the browsers event bubbling
        event.stopEvent();
        // create context menu
        cm = Ext.create('Ext.menu.Menu', {
            items: [{
                text: 'Add/Edit Alias',
                icon: 'resources/images/document_edit16x16.gif',
                handler: Ext.Function.bind(function(){
                    this.showTableAliasEditForm();
                }, this)
            }, {
                text: 'Remove Table',
                icon: 'resources/images/delete.gif',
                handler: Ext.Function.bind(function(){
                    // remove the sqltable
                    this.close();
                }, this)
            }, {
                text: 'Close Menu',
                icon: 'resources/images/cross.gif',
                handler: Ext.emptyFn
            }]
        });
        // show the contextmenu next to current mouse position
        cm.showAt(event.getXY());
    },
    showTableAliasEditForm: function(event, el){
        var table, header, title, titleId;
        table = ux.vqbuilder.sqlSelect.getTableById(this.tableId);
        header = this.getHeader();
        titleId = '#' + header.getId() + '_hd';
        title = this.down(titleId);
        header.remove(title);
        header.insert(0, [{
            xtype: 'textfield',
            flex: 0.95,
            parentCmp: header,
            parentTableModel: table,
            initComponent: function(){
            
                this.setValue(this.parentTableModel.get('tableAlias'));
                
                this.on('render', function(field, event){
                    // set focus to the textfield Benutzerkennung
                    field.focus(true, 200);
                }, this);
                
                this.on('specialkey', function(field, event){
                    if (event.getKey() == event.ENTER) {
                        if (field.getValue() != this.parentCmp.origValue) {
                            this.parentTableModel.set('tableAlias', field.getValue());
                            this.parentCmp.origValue = field.getValue();
                        }
                        this.removeTextField();
                        this.addTitle();
                    }
                }, this);
                
                this.on('blur', function(field, event){
                    if (field.getValue() != this.parentCmp.origValue) {
                        this.parentTableModel.set('tableAlias', field.getValue());
                        this.parentCmp.origValue = field.getValue();
                    }
                    this.removeTextField();
                    this.addTitle();
                }, this);
                
                this.callParent(arguments);
            },
            removeTextField: function(){
                var next;
                next = this.next();
                this.parentCmp.remove(next);
                this.parentCmp.remove(this);
            },
            addTitle: function(){
                var titleText;
                if (this.parentTableModel.get('tableAlias') != '') {
                    titleText = this.parentTableModel.get('tableAlias') + ' ( ' + this.parentTableModel.get('tableName') + ' )';
                }
                else {
                    titleText = this.parentTableModel.get('tableName');
                }
                this.parentCmp.insert(0, {
                    xtype: 'component',
                    ariaRole: 'heading',
                    focusable: false,
                    noWrap: true,
                    flex: 1,
                    id: this.parentCmp.id + '_hd',
                    style: 'text-align:' + this.parentCmp.titleAlign,
                    cls: this.parentCmp.baseCls + '-text-container',
                    renderTpl: this.parentCmp.getTpl('headingTpl'),
                    renderData: {
                        title: titleText,
                        cls: this.parentCmp.baseCls,
                        ui: this.parentCmp.ui
                    },
                    childEls: ['textEl']
                });
            }
        }, {
            xtype: 'component',
            flex: 0.05
        }]);
    },
    regStartDrag: function(){
        // save the mousedown state
        this.bMouseDown = true;
        // start the drag of the sprite
        this.shadowSprite.startDrag(this.getId());
    },
    moveWindow: function(event, domEl, opt){
        var relPosMovement;
        // check mousedown
        if (this.bMouseDown) {
            // get relative x and y values (offset)
            relPosMovement = this.getOffset('point');
            // move the sprite to the position of the window
            this.shadowSprite.onDrag(relPosMovement);
            // check if the sprite has any connections
            if (this.shadowSprite.bConnections) {
                // also move the associated connections 
                for (var i = ux.vqbuilder.connections.length; i--;) {
                    this.connection(ux.vqbuilder.connections[i]);
                }
            }
        }
    },
    getLeftRightCoordinates: function(obj1, obj2, aBBPos){
        var bb1, bb2, p = [], dx, leftBoxConnectionPoint, rightBoxConnectionPoint, dis, columHeight = 21, headerHeight = 46, LeftRightCoordinates = {};
        
        // BoundingBox Koordinaten f眉r beide Sprites abrufen
        
        bb1 = obj1.getBBox();
        // y Wert f眉r connection Points auf der linken und rechten Seite von bb1
        bb1.pY = bb1.y + headerHeight + ((aBBPos[0] - 1) * columHeight) + (columHeight / 2) - obj1.scrollTop;
        
        bb2 = obj2.getBBox();
        // y Wert f眉r connection Points auf der linken und rechten Seite von bb2
        bb2.pY = bb2.y + headerHeight + ((aBBPos[1] - 1) * columHeight) + (columHeight / 2) - obj2.scrollTop;
        
        // code f眉r linke boundingBox
        if (bb1.pY > (bb1.y + 4) && bb1.pY < (bb1.y + bb1.height - 4)) {
            p.push({
                x: bb1.x - 1, // Punkt auf linker Seite auf H枚he der verkn眉pften Spalte
                y: bb1.pY
            });
            p.push({
                x: bb1.x + bb1.width + 1, // Punkt auf rechter Seite auf H枚he der verkn眉pften Spalte
                y: bb1.pY
            });
        }
        else {
            if (bb1.pY < (bb1.y + 4)) {
                p.push({
                    x: bb1.x - 1, // Punkt auf linker Seite max. obere Position
                    y: bb1.y + 4
                });
                p.push({
                    x: bb1.x + bb1.width + 1, // Punkt auf rechter Seite max. obere Position
                    y: bb1.y + 4
                });
            }
            else {
                p.push({
                    x: bb1.x - 1, // Punkt auf linker Seite max. untere Position
                    y: bb1.y + bb1.height - 4
                });
                p.push({
                    x: bb1.x + bb1.width + 1, // Punkt auf rechter Seite max. untere Position
                    y: bb1.y + bb1.height - 4
                });
            };
                    };
        
        //  code f眉r rechte boundingBox
        if (bb2.pY > (bb2.y + 4) && bb2.pY < (bb2.y + bb2.height - 4)) {
            p.push({
                x: bb2.x - 1, // Punkt auf linker Seite auf H枚he der verkn眉pften Spalte
                y: bb2.pY
            });
            p.push({
                x: bb2.x + bb2.width + 1, // Punkt auf rechter Seite auf H枚he der verkn眉pften Spalte
                y: bb2.pY
            });
        }
        else {
            if (bb2.pY < (bb2.y + 4)) {
                p.push({
                    x: bb2.x - 1, // Punkt auf linker Seite max. obere Position
                    y: bb2.y + 4
                });
                p.push({
                    x: bb2.x + bb2.width + 1, // Punkt auf rechter Seite max. obere Position
                    y: bb2.y + 4
                });
            }
            else {
                p.push({
                    x: bb2.x - 1, // Punkt auf linker Seite max. untere Position
                    y: bb2.y + bb2.height - 4
                });
                
                p.push({
                    x: bb2.x + bb2.width + 1, // Punkt auf rechter Seite max. untere Position
                    y: bb2.y + bb2.height - 4
                });
            }
        };
        
        // Schleife 眉ber die Punkte der ersten BoundingBox
        for (var i = 0; i < 2; i++) {
            // Schleife 眉ber die Punkte der zweiten BoundingBox
            for (var j = 2; j < 4; j++) {
                // Berechnung der Offsets zwischen den jeweils vier Punkten beider BoundingBoxes
                dx = Math.abs(p[i].x - p[j].x), dy = Math.abs(p[i].y - p[j].y);
                // bb1 links mit bb2 rechts
                if (((i == 0 && j == 3) && dx < Math.abs(p[1].x - p[2].x)) || ((i == 1 && j == 2) && dx < Math.abs(p[0].x - p[3].x))) {
                    leftBoxConnectionPoint = p[i];
                    rightBoxConnectionPoint = p[j];
                }
            }
        };
        
        return {
            leftBoxConnectionPoint: leftBoxConnectionPoint,
            rightBoxConnectionPoint: rightBoxConnectionPoint
        };
        
    },
    connection: function(obj1, obj2, line, aBBPos){
        var LeftRightCoordinates, line1, line2, miniLine1, miniLine2, path, surface, color = typeof line == "string" ? line : "#000";
        
        if (obj1.line && obj1.from && obj1.to && obj1.aBBPos) {
            line = obj1;
            obj1 = line.from;
            obj2 = line.to;
            aBBPos = line.aBBPos;
        }
        
        // set reference to the wright surface
        surface = obj1.surface;
        
        // get coordinates for the left and right box
        LeftRightCoordinates = this.getLeftRightCoordinates(obj1, obj2, aBBPos);
        
        // check if the LeftBox is still on the left side or not
        if (LeftRightCoordinates.leftBoxConnectionPoint.x - LeftRightCoordinates.rightBoxConnectionPoint.x < 0) {
            line1 = 12;
            line2 = 12;
        }
        else {
            line1 = -12;
            line2 = -12;
        }
        // define the path between the left and the right box
        path = ["M", LeftRightCoordinates.leftBoxConnectionPoint.x, LeftRightCoordinates.leftBoxConnectionPoint.y, "H", LeftRightCoordinates.leftBoxConnectionPoint.x + line1, "L", LeftRightCoordinates.rightBoxConnectionPoint.x - line2, LeftRightCoordinates.rightBoxConnectionPoint.y, "H", LeftRightCoordinates.rightBoxConnectionPoint.x].join(",");
        
        miniLine1 = ["M", LeftRightCoordinates.leftBoxConnectionPoint.x, LeftRightCoordinates.leftBoxConnectionPoint.y, "H", LeftRightCoordinates.leftBoxConnectionPoint.x + line1].join(",");
        
        miniLine2 = ["M", LeftRightCoordinates.rightBoxConnectionPoint.x - line2, LeftRightCoordinates.rightBoxConnectionPoint.y, "H", LeftRightCoordinates.rightBoxConnectionPoint.x].join(",");
        
        //check if it is a new connection or not
        if (line && line.line) {
            // old connection, only change path
            line.bgLine &&
            line.bgLine.setAttributes({
                path: path
            }, true);
            line.line.setAttributes({
                path: path
            }, true);
            line.miniLine1.setAttributes({
                path: miniLine1
            }, true);
            line.miniLine2.setAttributes({
                path: miniLine2
            }, true);
        }
        else {
            // new connction, return new connection object
            return {
                line: Ext.create('Ext.draw.Sprite', {
                    type: 'path',
                    path: path,
                    stroke: color,
                    fill: 'none',
                    'stroke-width': 1,
                    surface: surface
                }).show(true),
                miniLine1: Ext.create('Ext.draw.Sprite', {
                    type: 'path',
                    path: miniLine1,
                    stroke: color,
                    fill: 'none',
                    'stroke-width': 2,
                    surface: surface
                }).show(true),
                miniLine2: Ext.create('Ext.draw.Sprite', {
                    type: 'path',
                    path: miniLine2,
                    stroke: color,
                    fill: 'none',
                    'stroke-width': 2,
                    surface: surface
                }).show(true),
                bgLine: Ext.create('Ext.draw.Sprite', {
                    type: 'path',
                    path: path,
                    opacity: 0,
                    stroke: '#fff',
                    fill: 'none',
                    'stroke-width': 10,
                    surface: surface
                }).show(true),
                from: obj1,
                to: obj2,
                aBBPos: aBBPos,
                uuid: this.createUUID()
            };
        }
    },
    initComponent: function(){
        var store, tableModel;
        
        this.connectionUUIDs = [];
        this.bMouseDown = false;
        
        // asign a uuid to the window, this builds relationship with sqlTable
        this.tableId = this.createUUID();
        
        
        store = Ext.create('Ext.data.Store', {
            autoLoad: true,
            fields: [{
                name: 'id',
                type: 'string'
            }, {
                name: 'tableName',
                type: 'string'
            }, {
                name: 'tableId',
                type: 'string',
                defaultValue: this.tableId
            }, {
                name: 'field',
                type: 'string'
            }, {
                name: 'extCmpId',
                type: 'string',
                defaultValue: this.id
            }, {
                name: 'type',
                type: 'string'
            }, {
                name: 'null',
                type: 'string'
            }, {
                name: 'key',
                type: 'string'
            }, {
                name: 'default',
                type: 'string'
            }, {
                name: 'extra',
                type: 'string'
            }],
            proxy: {
                type: 'ajax',
                url: 'data/database.cfc?method=getTableInfo',
                extraParams: {
                    tablename: this.title
                },
                reader: {
                    type: 'json'
                }
            }
        });
        
        // add sql table to ux.vqbuilder.sqlSelect tables store
        // also asign same id as stores uuid
        tableModel = Ext.create('Ext.ux.window.visualsqlquerybuilder.SQLTableModel', {
            id: this.tableId,
            tableName: this.title,
            tableAlias: ''
        });
        ux.vqbuilder.sqlSelect.addTable(tableModel);
        
        this.items = [{
            xtype: 'sqltablegrid',
            store: store
        }];
        
        this.callParent(arguments);
    },
    getOffset: function(constrain){
        var xy = this.dd.getXY(constrain), s = this.dd.startXY;
        // return the the difference between the current and the drag&drop start position
        return [xy[0] - s[0], xy[1] - s[1]];
    },
    createUUID: function(){
        // http://www.ietf.org/rfc/rfc4122.txt
        var s = [];
        var hexDigits = "0123456789abcdef";
        for (var i = 0; i < 36; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23] = "-";
        
        var uuid = s.join("");
        return uuid;
    },
    beforeShow: function(){
        var aWin, prev, o;
        // cascading window positions
        if (this.cascadeOnFirstShow) {
            o = (typeof this.cascadeOnFirstShow == 'number') ? this.cascadeOnFirstShow : 20;
            // get all instances from xtype sqltable
            aWin = Ext.ComponentQuery.query('sqltable');
            // start position if there is only one table
            if (aWin.length == 1) {
                this.x = o;
                this.y = o;
            }
            else {
                // loop through all instances from xtype sqltable
                for (var i = 0, l = aWin.length; i < l; i++) {
                    if (aWin[i] == this) {
                        if (prev) {
                            this.x = prev.x + o;
                            this.y = prev.y + o;
                        }
                    }
                    if (aWin[i].isVisible()) {
                        prev = aWin[i];
                    }
                }
            }
            this.setPosition(this.x, this.y);
        }
    }
});

Ext.define('Ext.ux.window.VisualSQLQueryBuilder', {
    extend: 'Ext.window.Window',
    alias: ['widget.qbwindow'],
    height: 620,
    width: 1000,
    layout: {
        type: 'border'
    },
    title: 'Visual SQL Query Builder',
    items: [{
        xtype: 'sqloutputpanel',
        border: false,
        region: 'center',
        autoScroll: true,
        html: '<pre class="brush: sql">SQL Output Window</pre>',
        margin: 5,
        height: 150,
        split: true
    }, {
        xtype: 'panel',
        border: false,
        height: 400,
        margin: 5,
        layout: {
            type: 'border'
        },
        region: 'north',
        split: true,
        items: [{
            xtype: 'sqltablepanel',
            border: false,
            region: 'center',
            height: 280,
            split: true,
            layout: 'fit'
        }, {
            xtype: 'sqlfieldsgrid',
            border: false,
            region: 'south',
            height: 120,
            split: true
        }, {
            xtype: 'sqltabletree',
            border: false,
            region: 'west',
            width: 200,
            height: 400,
            split: true
        }]
    }],
    initComponent: function(){
    
        // create user extension namespace ux.vqbuilder
        Ext.namespace('ux.vqbuilder');
        
        // disable gutter (linenumbers) and toolbar for SyntaxHighlighter
        SyntaxHighlighter.defaults['gutter'] = false;
        SyntaxHighlighter.defaults['toolbar'] = false;
        
        ux.vqbuilder.connections = [];
        
        ux.vqbuilder.sqlSelect = Ext.create('Ext.ux.window.visualsqlquerybuilder.SQLSelect');
        
        // add toolbar to the dockedItems
        this.dockedItems = [{
            xtype: 'toolbar',
            dock: 'top',
            items: [{
                xtype: 'tbfill'
            }, {
                text: "Save",
                icon: "resources/images/icon-save.gif"
            }, {
                text: "Run",
                icon: "resources/images/run.png"
            }]
        }];
        
        this.callParent(arguments);
    }
});


Extjs4实现的Ext.ux.window.VisualSQLQueryBuilder.rar

 

SQL在线查询设计器,强大的SQL在线查询工具

 

下载地址:http://download.csdn.net/download/luck332/4897329

分享到:
评论

相关推荐

    Sql查询分析器

    "Sql查询分析器"是一款专为SQLServer设计的实用工具,它使得用户可以直接与数据库进行交互,执行SQL查询,从而高效地管理和分析数据。这款工具的便捷之处在于,它是一个可执行的exe文件,无需安装,只需解压缩后直接...

    sqlserver查询分析器 win10可用

    6. **高级特性**:SSMS支持T-SQL调试、性能调优(如查询分析器和索引顾问)、数据库设计(表、视图、存储过程等)、备份恢复、权限管理等高级功能。 7. **第三方查询分析器**:除了官方的SSMS,还有其他第三方工具...

    sql2000查询分析器

    《SQL2000查询分析器深度解析与应用指南》 SQL Server 2000是微软公司推出的一款关系型数据库管理系统,它以其强大的数据处理能力和丰富的功能深受广大IT从业者的喜爱。其中,SQL2000查询分析器是数据库管理员和...

    sqlserver查询分析器独立版单exe文件,支持2008,2012

    SQL Server查询分析器是Microsoft SQL Server数据库管理系统的重要组成部分,它为数据库管理员和开发人员提供了一个交互式的环境,用于编写、测试和执行SQL语句以及Transact-SQL脚本。在这个场景中,我们讨论的是一...

    可视的SQL查询设计器

    【可视的SQL查询设计器】是一种用户友好的工具,它允许非技术用户或程序员通过图形界面构建和执行SQL查询,而无需直接编写SQL语句。这种设计器通常包含一系列功能,如表选择、字段拖放、条件设定、排序和分组等,以...

    extjs 在线sql查询

    这个组件提供了一个可视化的SQL构建器,让用户可以通过拖拽和配置操作来创建复杂的SQL查询,而无需直接编写SQL语句。这对于那些不熟悉SQL语法或者希望减少手动输入错误的用户来说非常有用。 HTML580 可能是指这个...

    sql查询分析器sql查询分析器

    SQL查询分析器是一种重要的数据库管理工具,它允许用户编写、测试和优化SQL语句,以高效地查询和操作数据。在数据库开发、管理和维护中,SQL查询分析器扮演着不可或缺的角色。下面将详细介绍SQL查询分析器及其相关...

    SQL查询分析器SQL查询分析器SQL查询分析器

    7. **数据建模与设计**:一些高级的SQL查询分析器还支持数据建模,包括ER图的绘制、表结构的设计和关系的分析,辅助数据库的规范化和设计优化。 8. **兼容性与互操作性**:SQL查询分析器通常支持多种数据库系统,如...

    SQLSERVER查询分析器

    【SQLSERVER查询分析器】是一款专为SQL Server数据库设计的高效工具,旨在帮助开发者和数据库管理员更好地理解和优化SQL查询性能。这款分析器不仅提供基本的查询执行功能,还具备自动生成增、删、改(INSERT、DELETE...

    SQL2005查询工具 SQLServer2005_SSMSEE

    标题中的“SQL2005查询工具”指的是SQL Server Management Studio Express(SSMSEE),这是一个轻量级版本的SQL Server Management Studio,专为SQL Server 2005设计。SSMSEE提供了图形化的界面,让数据库管理员和...

    Sqlserver MSDE查询分析器界面

    【SQL Server MSDE查询分析器界面详解】 SQL Server Desktop Engine(简称MSDE)是Microsoft公司推出的一款轻量级数据库引擎,它提供了与SQL Server标准版相似的功能,但针对小型应用程序和开发环境。在进行数据...

    可视化sql查询语句生成器

    可视化SQL查询语句生成器是一种高效且用户友好的工具,专为那些不熟悉或不习惯编写SQL代码的用户设计。这种工具通常具有图形用户界面(GUI),允许用户通过直观的界面来构建复杂的查询,而无需直接输入SQL命令。在...

    SQL简易分析查询器

    "SQL简易分析查询器"是一款专为用户设计的轻量级数据库查询工具,它简化了SQL查询过程,使得数据分析更为便捷。这款软件的核心特点在于其绿色小巧的特性,无需安装即可使用,大大降低了用户的使用门槛,尤其适合那些...

    SQLSERVER查询分析器v2.0

    SQLSERVER查询分析器v2.0是一款专为.NET软件开发设计的强大工具,它在原有的v1.0基础上进行了重大升级,新增了C#代码生成器和存储过程生成器等功能,极大地提升了开发人员的工作效率和代码质量。 首先,C#代码生成...

    易语言SQLSERVER查询分析器

    《易语言SQLSERVER查询分析器》是一款专为易语言编程环境设计的工具,它提供了连接、操作和分析SQL Server数据库的能力。源码的开放性使得开发者可以深入理解其内部工作原理,同时也为自定义功能和扩展提供了可能。...

    SQL数据库查询分析器

    SQL数据库查询分析器是一款专为数据库管理与数据分析设计的实用工具,它提供了绿色、简易的界面,使得用户能够轻松地进行SQL查询操作。这款分析器适用于多种SQL数据库系统,包括但不限于MySQL、SQL Server、Oracle、...

    SQLSERVER查询分析器.e

    《SQLSERVER查询分析器》是一款基于易语言开发的工具,主要功能是用于解析和执行SQLSERVER的查询语句。此程序充分利用了易语言的扩展界面支持库和数据库操作支持库,为用户提供了方便快捷的SQL查询分析环境。下面将...

Global site tag (gtag.js) - Google Analytics