/** * Project AMDA-NG * Name CatalogUI.js * @class amdaUI.catalogUI * @extends Ext.container.Container * @brief Catalog Module UI definition (View) * @author elena */ Ext.define('amdaUI.CatalogUI', { extend: 'Ext.container.Container', alias: 'widget.panelCatalog', requires: [ 'Ext.grid.plugin.BufferedRenderer', 'amdaUI.StatisticalPlug' ], isCatalog : true, statics: { COL_TO_HIDE_DURATION : 'colToHideDuration' }, constructor: function(config) { this.init(config); this.callParent(arguments); this.toReconfigure = true; if (this.object) { this.loadObject(); } }, setObject : function (object, toReconfigure) { if (toReconfigure) this.toReconfigure = true; // set object this.object = object; // load object into view this.loadObject(); // show the default duration column this.TTGrid.headerCt.getGridColumns(); Ext.Array.each(this.TTGrid.headerCt.getGridColumns(), function(item,index,all){ // if item is the default duration column if ( item.id == amdaUI.CatalogUI.COL_TO_HIDE_DURATION+'2' ) { // show this column item.show(); } }); // fire the refresh event (to statistical plugin) this.fireEvent("refresh"); // global event myDesktopApp.EventManager.fireEvent("refresh"); }, /** * set params description into this.object */ setParamInfo : function(parameters) { var params = []; Ext.Array.each(parameters, function(item, index) { params[index] = item; }, this); this.object.set('parameters', params); this.object.set('nbParameters', params.length); }, /** * update this.object from form */ updateObject : function(){ // get the basic form var basicForm = this.formPanel.getForm(); var updateStatus = true; var fieldsWithoutName = basicForm.getFields().items; Ext.Array.each(fieldsWithoutName, function(item, index,allItems){ if(item !== this.fieldName) { if (!item.isValid()) { // set update isn't allowed updateStatus = false; } } }, this); // if the update is allowed if (updateStatus) { /// real object update // update TimeTable object with the content of form basicForm.updateRecord(this.object); } // return the update status return updateStatus; }, addInterval : function(start, stop) { var row = this.TTGrid.getStore().getTotalCount(); var me = this; this.TTGrid.getSelectionModel().deselectAll(); AmdaAction.addTTCacheInterval({'start' : start, 'stop' : stop, 'index' : row, 'isCatalog' : true},function (result, e) { this.status = result.status; if (!this.TTGrid.getStore().loading) { this.TTGrid.getStore().reload({ callback : function(records, options, success) { me.TTGrid.getView().bufferedRenderer.scrollTo(row, false, function() { me.TTGrid.getView().select(row); }, me); } }); } }, this); }, updateCount : function() { this.object.set('nbIntervals',this.TTGrid.getStore().getTotalCount()); this.formPanel.getForm().findField('nbIntervals').setValue(this.object.get('nbIntervals')); }, generateTT : function(){ console.log(this); if(this.fclose()){ Ext.Msg.confirm('Generate TT', 'Current Catalog has been modified.\nDo you want to include these changes in the generated Time Table ?' , function (btn, text){ if (btn == 'yes'){ // mark this.closed as true before the call to close() as that will fire the beforeclose event again if(this.object.get('id') ==""){ // case of creation of catalog this.saveCatalog(true); }else{ // casse existing catalog this.saveProcess(false,true); } return //win.close(); } }, this); }else{ this.createTT(this.object.get('id')); } }, createTT : function(catId){ var catObj = Ext.create('amdaModel.TimeTable'); var timeTabNode = Ext.create('amdaModel.TimeTableNode',{leaf : true}); catObj.set('relatedCatalogId', catId) creatDate=new Date(this.object.get('created')); date=Ext.Date.format(creatDate,'Y-m-d\\TH:i:s'); descr='Generated by CDPP/Amda Catalog Module \n'+ 'From Catalog: '+this.object.get('name')+'\nOn: '+date+'\n'; catObj.set('description', descr+this.object.get('description')); timeTabNode.set('object',catObj); var explorerTree = Ext.getCmp(amdaUI.ExplorerUI.RESRC_TAB.TREE_ID); var ttRootNode = explorerTree.getRootNode().findChild('id', 'timeTable-treeRootNode', true); amdaModel.InteractiveNode.preloadNodes(ttRootNode.getRootNode(), function() { // edit newNode into Parameter Module with node as contextNode timeTabNode.editInModule(); }); }, onAfterInit: function(result, e) { var me = this; if (!result) { myDesktopApp.errorMsg(e.message); Ext.defer(function(){Ext.Msg.toFront()},10); return; } else if (!result.success) { if (result.message) myDesktopApp.errorMsg(result.message); else myDesktopApp.errorMsg('Unknown error during catalog cache initialisation'); Ext.defer(function(){Ext.Msg.toFront()},10); return; } if (me.toReconfigure) { var fieldsConfig = [ { name : 'start', type : 'date', dateFormat: 'Y-m-d\\TH:i:s', convert: function(value,rec) { if (!Ext.isDate(value)){ var valueString = new String(value); return new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' ')); } return value; } }, { name : 'stop', type : 'date', dateFormat: 'Y-m-d\\TH:i:s', convert: function(value,rec) { if (!Ext.isDate(value)){ var valueString = new String(value); return new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' ')); } return value; } }, { name:'durationHour', type: 'float', convert: function(value, rec){ if (rec.get('stop') && rec.get('start') && (rec.get('stop')-rec.get('start'))>=0) { return (rec.get('stop') - rec.get('start'))/3600000.0; } }, persist: false }, { name: 'durationMin', type: 'float', convert: function(value, rec){ if (rec.get('stop') && rec.get('start') && (rec.get('stop')-rec.get('start'))>=0) { return (rec.get('stop') - rec.get('start'))/60000.0; } }, persist: false }, { name: 'durationSec', type: 'float', convert: function(value, rec){ if (rec.get('stop') && rec.get('start') && (rec.get('stop')-rec.get('start'))>=0) { return (rec.get('stop') - rec.get('start'))/1000.0; } }, persist: false }, { name: 'cacheId', type : 'int'}, { name: 'isNew', type : 'boolean', defaultValue: false }, { name: 'isModified', type : 'boolean', defaultValue: false} ]; var updateDurationColumnsVisibility = function(columns, visibleId) { Ext.Array.each(columns, function(item,index){ // if item is a column to hide automatically if ( Ext.util.Format.substr(item.id, 0, amdaUI.CatalogUI.COL_TO_HIDE_DURATION.length) == amdaUI.CatalogUI.COL_TO_HIDE_DURATION ) { // if item isn't the column which is being declared and is not hidden if ( item.id != visibleId && !item.isHidden() ){ // hide this column item.hide(); } } }); }; var columnsConfig = [ { xtype: 'rownumberer', width: 50, renderer: function(value, metaData, record){ var msg = record.index + 1; if (record.get('isNew') || record.get('isModified')) { msg += ' *'; metaData.style = 'font-weight: bold' } return msg; } }, { xtype: 'datecolumn', text: 'Start Time', format: 'Y-m-d\\TH:i:s', sortable : true, dataIndex: 'start', width : 120, menuDisabled: false, editor : { xtype:'datefield', allowBlank:false, hideTrigger: true, format : 'Y-m-d\\TH:i:s' } }, { xtype: 'datecolumn', text: 'Stop Time', format: 'Y-m-d\\TH:i:s', sortable : true, dataIndex: 'stop', width : 120, menuDisabled: false, editor : { xtype:'datefield', allowBlank:false, hideTrigger: true, format : 'Y-m-d\\TH:i:s' } }, { xtype: 'gridcolumn', text: 'Duration (hour)', sortable : true, dataIndex: 'durationHour', width : 120, menuDisabled: false, hidden:true, id: amdaUI.CatalogUI.COL_TO_HIDE_DURATION+'1', renderer: function(value) { return Ext.util.Format.number(value,'0.00'); }, listeners: { beforeshow : function(){ updateDurationColumnsVisibility(this.ownerCt.getGridColumns(), amdaUI.CatalogUI.COL_TO_HIDE_DURATION+'1'); } } }, { xtype: 'gridcolumn', text: 'Duration (Min)', sortable : true, dataIndex: 'durationMin', width : 120, menuDisabled: false, hidden:false, id: amdaUI.CatalogUI.COL_TO_HIDE_DURATION+'2', renderer: function(value) { return Ext.util.Format.number(value,'0.00'); }, listeners: { beforeshow : function(){ updateDurationColumnsVisibility(this.ownerCt.getGridColumns(), amdaUI.CatalogUI.COL_TO_HIDE_DURATION+'2'); } } }, { xtype: 'gridcolumn', text: 'Duration (Sec)', sortable : true, dataIndex: 'durationSec', width : 120, menuDisabled: false, hidden:true, id: amdaUI.CatalogUI.COL_TO_HIDE_DURATION+'3', renderer: function(value) { return Ext.util.Format.number(value,'0.00'); }, listeners: { beforeshow : function(){ updateDurationColumnsVisibility(this.ownerCt.getGridColumns(), amdaUI.CatalogUI.COL_TO_HIDE_DURATION+'3'); } } } ]; Ext.Array.each(result.parameters, function(obj, index) { var field = { name: 'param'+(index+2) }; var column = { text: obj.name, sortable : true, dataIndex: 'param'+(index+2), menuDisabled: false }; switch (obj.type) { case 1: //dateTime field = Ext.apply({}, field, { type : 'date', dateFormat: 'Y-m-d\\TH:i:s', convert: function(value,rec) { if (!Ext.isDate(value)){ var valueString = new String(value); return new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' ')); } return value; } }); column = Ext.apply({}, column, { xtype: 'datecolumn', width : 120, editor : { xtype:'datefield', allowBlank:false, hideTrigger: true, format : 'Y-m-d\\TH:i:s' } }); break; default: field = Ext.apply({}, field, { type: 'string' }); column = Ext.apply({}, column, { width : 50. * parseInt(obj.size), editor: 'textfield' }); } fieldsConfig.push(field); columnsConfig.push(column); }); var store = Ext.create('Ext.data.Store', { fields: fieldsConfig, autoDestroy: false, pageSize : 200, buffered : true, purgePageCount: 0, remoteSort: true, proxy: { type: 'direct', api : { read : AmdaAction.readTTCacheIntervals }, // remplir automatiquement tt, sharedtt , catalog, shared catalog extraParams : {'typeTT' : 'catalog'}, reader: { type: 'json', root: 'intervals', totalProperty : 'totalCount' } }, listeners: { scope : me, load: function(store,records) { // myDesktopApp.EventManager.fireEvent('refresh'); me.TTGrid.getView().refresh(); me.TTGrid.getSelectionModel().refresh(); me.updateCount(); //Statistical plugin this.fireEvent("refresh"); } } }); me.TTGrid.reconfigure(store, columnsConfig); } me.TTGrid.getSelectionModel().deselectAll(); // // // clear filters // me.TTGrid.getStore().clearFilter(true); // // clear sort me.TTGrid.getStore().sorters.clear(); // me.TTGrid.getStore().sorters = new Ext.util.MixedCollection(); //set cache token to the Catalog object me.object.set('cacheToken', result.token); me.setParamInfo(result.parameters); me.TTGrid.getStore().load(); me.status = result.status; //Statistical plugin me.fireEvent("refresh"); }, /** * load object catalog into this view */ loadObject : function(){ // load object into form this.formPanel.getForm().loadRecord(this.object); this.status = null; if (this.object.get('fromPlugin') && (this.object.get('objName') != '')){ if (this.object.get('objFormat') && this.object.get('objFormat') != ''){ //From uploaded file AmdaAction.initTTCacheFromUploadedFile(this.object.get('objName'), this.object.get('objFormat'), this.isCatalog, this.onAfterInit, this); } else { //From tmp object (ie Statistics result) AmdaAction.initTTCacheFromTmpObject(this.object.get('folderId'), this.object.get('objName'), this.isCatalog, this.onAfterInit, this); } } else { var typeTT = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id).linkedNode.data.nodeType; if (this.object.get('id') == '') { AmdaAction.initTTCache(this.isCatalog, this.object.get('nbParameters'), this.onAfterInit,this); } else { //From existing TT file AmdaAction.initTTCacheFromTT(this.object.get('id'), typeTT, this.onAfterInit, this); } } //Statistical plugin this.fireEvent("refresh"); }, checkIntervalsStatusForSave : function(onStatusOk) { onStatusOk(); }, /* * save method called by Save button */ saveProcess : function(toRename, onAfterSave) { var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id); // store / columns are the same - not needed to reconfigure grid this.toReconfigure = false; // if save shared catalog if (module.contextNode && (module.contextNode.get('id') == 'sharedcatalog-treeRootNode')) { module.linkedNode = null; module.createLinkedNode(); module.createObject(this.object.getJsonValues()); var obj = module.linkedNode.get('object'); // synchronisation of objects this.object = obj; module.linkedNode.create({callback : function() {if (onAfterSave) this.createTT(this.object.get('id'));}, scope : this}); } // if the name has been modified this is a creation else if (this.fclose()) { if (this.object.isModified('name') || this.object.get('fromPlugin')) { // if object already has an id : it's a 'rename' of an existing if (this.object.get('id')){ // the context Node is the parent node of current edited one var contextNode = module.linkedNode.parentNode; // link a new node to the TimeTableModule module.createLinkedNode(); // set the contextNode module.linkedNode.set('contextNode',contextNode); // create a new object linked module.createObject(this.object.getJsonValues()); var obj = module.linkedNode.get('object'); // synchronisation of objects this.object = obj; if (toRename) module.linkedNode.toRename = true; } module.linkedNode.create({callback : function() {module.linkedNode.update({callback : function() {if (onAfterSave) this.createTT(this.object.get('id'));}, scope : this});}, scope : this}); } else { //update module.linkedNode.update({callback : function() {if (onAfterSave) this.createTT(this.object.get('id'));}, scope : this}); } } }, saveCatalog : function (onAfterSave){ if (this.updateObject()) { var basicForm = this.formPanel.getForm(); // if there's at least one record in the store of TTGrid if (this.TTGrid.getStore().getTotalCount() > 0) { // update TimeTable object which the content of form basicForm.updateRecord(this.object); var me = this; this.checkIntervalsStatusForSave(function () { //Name validation var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id); if (!module) return; module.linkedNode.isValidName(me.fieldName.getValue(), function (res) { if (!res) { me.fieldName.validFlag = 'Error during object validation'; myDesktopApp.errorMsg(me.fieldName.validFlag); me.fieldName.validate(); return; } if (!res.valid) { if (res.error) { if (res.error.search('subtree') != -1) { Ext.MessageBox.show({title:'Warning', msg: res.error+'
Do you want to overwrite it?', width: 300, buttons: Ext.MessageBox.OKCANCEL, fn : me.overwriteProcess, icon: Ext.MessageBox.WARNING, scope : me }); me.fieldName.validFlag = true; } else me.fieldName.validFlag = res.error; } else { me.fieldName.validFlag = 'Invalid object name'; myDesktopApp.errorMsg(me.fieldName.validFlag); } me.fieldName.validate(); return; } me.fieldName.validFlag = true; me.fieldName.validate(); me.saveProcess(false, onAfterSave); }); }); } else { Ext.Msg.alert('No intervals', 'Your catalog is invalid,
you must have at least one interval'); } } }, /** * overwrite metod called by Save button */ overwriteProcess : function(btn) { if (btn == 'cancel') return; this.fieldName.clearInvalid(); this.saveProcess(true); }, /** * Check if changes were made before closing window * @return true if changes */ fclose : function() { if (this.status == null) return false; var isDirty = this.formPanel.getForm().isDirty() || (this.status.isModified) || (this.status.nbModified > 0) || (this.status.nbNew > 0); return isDirty; }, init : function (config) { this.object = config.object; this.fieldName = new Ext.form.field.Text({ fieldLabel: 'Name', allowBlank : false, stripCharsRe: /(^\s+|\s+$)/g, emptyText: 'Please no spaces!', name: 'name', validateOnChange: false, validateOnBlur: false, validFlag: false, validator : function() { return this.validFlag; } }); var cellEditing = Ext.create('Ext.grid.plugin.CellEditing',{ // clicksToEdit: 2, onEditComplete : function(ed, value, startValue) { var me = this, activeColumn = me.getActiveColumn(), context = me.context, record; if (activeColumn) { record = context.record; me.setActiveEditor(null); me.setActiveColumn(null); me.setActiveRecord(null); context.value = value; if (!me.validateEdit()) { me.editing = false; return; } // Only update the record if the new value is different than the // startValue. When the view refreshes its el will gain focus if (!record.isEqual(value, startValue)) { var obj = {}; obj['cacheId'] = record.get('cacheId'); obj['isCatalog'] = true; obj[activeColumn.dataIndex] = value; //Interval is modified on the server side me.editing = true; AmdaAction.modifyTTCacheInterval(obj, function (result, e) { var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id); if (module) module.getUiContent().status = result.status; if (!context.store.loading) { context.grid.getSelectionModel().deselectAll(); context.store.reload({ callback : function(records, options, success) { context.view.bufferedRenderer.scrollTo(context.rowIdx, true, function() { me.fireEvent('edit', me, context); me.editing = false; }, me); } }); } else { me.editing = false; } }, this); } else me.editing = false; } } }); this.TTGrid = Ext.create('Ext.grid.Panel', { height: 530, columns: [ ], frame: true, columnLines: true, selModel: {pruneRemoved: false}, // selType: 'cellmodel', plugins: [ cellEditing, { ptype : 'bufferedrenderer'} ], dockedItems: [{ xtype: 'toolbar', items: [{ iconCls: 'icon-add', scope: this, handler: function(){ cellEditing.cancelEdit(); var store = this.TTGrid.getStore(); var selection = this.TTGrid.getView().getSelectionModel().getSelection()[0]; var row = 0; if (selection) row = store.indexOf(selection) + 1; this.TTGrid.getSelectionModel().deselectAll(); var me = this; AmdaAction.addTTCacheInterval({'index' : row, 'isCatalog' : true}, function (result, e) { this.status = result.status; if (!this.TTGrid.getStore().loading) { this.TTGrid.getStore().reload({ callback : function(records, options, success) { me.TTGrid.getView().bufferedRenderer.scrollTo(row, false, function() { me.TTGrid.getView().select(row); cellEditing.startEditByPosition({row: row, column: 1}); }, me); } }); } }, this); } },{ iconCls: 'icon-delete', disabled: true, itemId: 'delete', scope: this, handler: function(){ var selection = this.TTGrid.getView().getSelectionModel().getSelection()[0]; if (selection) { var rowId = selection.get('cacheId'); this.TTGrid.getSelectionModel().deselectAll(); AmdaAction.removeTTCacheIntervalFromId(rowId, this.isCatalog, function (result, e) { this.status = result.status; if (!this.TTGrid.getStore().loading) { this.TTGrid.getStore().reload(); } }, this); } } }] }] }); this.formPanel = Ext.create('Ext.form.Panel', { region : 'center', layout: 'hbox', model : 'amdaModel.Catalog', trackResetOnLoad : true, // reset to the last loaded record bodyStyle: {background : '#dfe8f6'}, defaults: { border : false, align: 'stretch', bodyStyle: {background : '#dfe8f6'}, padding: '3'}, fieldDefaults: { labelWidth: 80, labelAlign : 'top' }, items: [{ xtype: 'form', flex: 1, buttonAlign: 'left', // title : 'Information', layout: {type: 'vbox', pack: 'start', align: 'stretch'}, items : [ this.fieldName, { xtype: 'fieldcontainer', layout: 'hbox', items: [{ xtype:'datefield', fieldLabel:'Creation date', name: 'created', disabled: true, hideTrigger: true, format: 'Y/m/d H:i:s' }, { xtype: 'splitter' }, { xtype:'textfield', fieldLabel: 'Intervals', name: 'nbIntervals', disabled: true } ] }, { xtype: 'textarea', name: 'description', fieldLabel: 'Description', height: 200 }, { xtype: 'component', height: 90 }], dockedItems:[{ xtype: 'toolbar', dock: 'bottom', ui: 'footer', items: [{ type: 'button', text: 'Create New Catalog', scope : this, handler: function () { var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id); if (!module) return; module.createLinkedNode(); module.createObject(); var obj = module.linkedNode.get('object'); var me = this; Ext.Msg.prompt('Define Parameters', 'Please enter parameters number:', function(btn, text){ if (btn == 'ok'){ module.createLinkedNode(); module.createObject(); var obj = module.linkedNode.get('object'); var nbParam = parseInt(text); if ((nbParam <= 0) || (nbParam > 100)) { nbParam = 1; } obj.set('nbParameters', nbParam); me.setObject(obj,true); } }, this); } }] }, { xtype: 'toolbar', dock: 'bottom', ui: 'footer', items: [ { type: 'button', text: 'Save', scope : this, handler: function () { this.saveCatalog(); } },{ type: 'button', text: 'Reset', scope : this, handler: function() { var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id); // module.createLinkedNode(); // module.createObject(); this.setObject(module.getLinkedNode().get('object'), true); } }, // { // type: 'button', // text: 'Share', // scope : this, // handler: function() { // var me = this; // myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id, true, function (module) { // var catalog = module.getLinkedNode().get('object'); // module.shareCatalog({'name' : catalog.get('text'), 'id' : catalog.get('id')}); // }); // } // }, ] }, //statistical info { xtype: 'toolbar', dock: 'bottom', ui: 'footer', items:[{ xtype: 'button', text: 'Statistical info', scope: this, //dock: 'bottom', //ui: 'footer', handler: function() { this.fireEvent('info','catalogUI'); } }, { type: 'button', text: 'Visualize', scope: this, handler: function() { var me = this; myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.visu.id, true, function (module) { //temporary linked node - as Visu module is 'pseudo' interactive - no 'save', no 'execute' var temporaryNode = Ext.create('amdaModel.CatalogNode', { leaf : true }); if (temporaryNode) temporaryNode.set('object',me.object); module.setLinkedNode(temporaryNode); module.createWindow(); }); } } ] }, { xtype: 'toolbar', dock: 'bottom', ui: 'footer', items:[{ xtype: 'button', text: 'Generate Time Table', scope: this, //dock: 'bottom', //ui: 'footer', handler: function() { this.generateTT(this.object.get('id')); } }]}, ] }, { xtype: 'form', bodyStyle: {background : '#dfe8f6'}, //padding: '3', flex: 2, items : [ this.TTGrid ] }] }); this.TTGrid.getSelectionModel().on('selectionchange', function(selModel,selections) { this.TTGrid.down('#delete').setDisabled(selections.length === 0); }, this); var myConf = { layout: 'border', items: [ this.formPanel, { xtype: 'panel', region: 'south', title: 'Information', collapsible: true, collapseMode: 'header', height: 100, autoHide: false, bodyStyle: 'padding:5px', iconCls: 'icon-information', loader: { autoLoad: true, url: helpDir+'catalogHOWTO' } } ] , plugins: [ {ptype: 'statisticalPlugin'} ] }; Ext.apply (this, Ext.apply(arguments, myConf)); } });