Commit c4fe127d1f4aa58c68cb7f8e333b3fbd8b063a9c

Authored by Benjamin Renard
2 parents ccafb489 4667889e

Merge branch 'master' into develop

generic_data/operations.json
1 1 {"nodes": [
2 2 {"nodeType" : "request", "text" : "Plot", "id" : "request-treeRootNode"} ,
  3 + {"nodeType" : "download", "text" : "Download", "id" : "download-treeRootNode"} ,
3 4 {"nodeType" : "condition","text" : "Data Mining","id" : "condition-treeRootNode" }
4 5 ]}
... ...
help/info.html
... ... @@ -18,10 +18,7 @@
18 18 <h3>AMDA DOCS</h3>
19 19 <div class="title">
20 20 <ul>
21   - <li><h4>Presentations</h4>
22   - <ul>
23   - <li><a href="http://cdpp.irap.omp.eu/index.php/ressources/presentations" target="_blank">CDPP/AMDA</a>
24   - </ul>
  21 + <li><h4><a href="https://doi.org/10.1016/j.pss.2021.105214" target="_blank">Article AMDA</h4></a></br>
25 22 <li><h4>Publications</h4>
26 23 <ul>
27 24 <li> <a href="http://cdpp.irap.omp.eu/index.php/ressources/publications/tools-and-the-vo" target="_blank">
... ...
js/app/controllers/DownloadModule.js
... ... @@ -22,7 +22,6 @@ Ext.define(&#39;amdaDesktop.DownloadModule&#39;, {
22 22 * @cfg {String} data models
23 23 * @required
24 24 */
25   - objectDataModel : 'amdaModel.Download',
26 25 nodeDataModel : 'amdaModel.DownloadNode',
27 26  
28 27 /**
... ... @@ -30,21 +29,11 @@ Ext.define(&#39;amdaDesktop.DownloadModule&#39;, {
30 29 * @required
31 30 */
32 31 width: 600,
33   - height: 600,
  32 + height: 620,
34 33 uiType : 'panelDownload',
35 34 helpTitle : 'Help on Download Module',
36 35 helpFile : 'downloadHelp',
37 36  
38   - /**
39   - * @override
40   - */
41   - createWindow : function() {
42   - if (!this.linkedNode){
43   - this.setLinkedNode(amdaModel.DownloadNode);
44   - }
45   - this.callParent(arguments);
46   - },
47   -
48 37 saveState: function() {
49 38 var uiContent = this.getUiContent();
50 39 var form = uiContent.down('form').getForm();
... ... @@ -56,5 +45,26 @@ Ext.define(&#39;amdaDesktop.DownloadModule&#39;, {
56 45 getState : function() {
57 46 // return Ext.state.Manager.get(this.id + '_form');
58 47 return Ext.state.Manager.get('timeinterval');
  48 + },
  49 +
  50 + addParameter: function(paramNode) {
  51 + var me = this;
  52 + var desktop = this.app.getDesktop();
  53 + var win = desktop.getWindow(this.id);
  54 + if (win) {
  55 + me.getUiContent().addParameter(paramNode, false);
  56 + win.show();
  57 + }
  58 + else {
  59 + this.createWindow(function () {
  60 + me.getUiContent().addParameter(paramNode, true);
  61 + });
  62 + }
  63 + },
  64 +
  65 + editFromJsonData: function(jsonData) {
  66 + this.createLinkedNode();
  67 + this.createObject(jsonData);
  68 + this.createWindow();
59 69 }
60   -});
61 70 \ No newline at end of file
  71 +});
... ...
js/app/controllers/JobsMgr.js
... ... @@ -53,7 +53,7 @@
53 53 Ext.define('amdaDesktop.JobsMgr', {
54 54 extend: 'Ext.AbstractManager',
55 55 first: true,
56   - interval: 60000,
  56 + interval: 10000,
57 57 jobTree: null,
58 58 jobsError: 0,
59 59 jobsFinished: 0,
... ...
js/app/controllers/PlotModule.js
... ... @@ -300,5 +300,30 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, {
300 300  
301 301 isMultiPlot : function() {
302 302 return this.multiPlotWin && !this.multiPlotWin.isHidden();
  303 + },
  304 +
  305 + editInDownloadModule: function(plotNode) {
  306 + var plotValues = plotNode.get('object').getJsonValues();
  307 + var downloadValues = new Object();
  308 + downloadValues.timesrc = plotValues.timesrc;
  309 + downloadValues.startDate = plotValues.startDate;
  310 + downloadValues.stopDate = plotValues.stopDate;
  311 + downloadValues.durationDay = plotValues.durationDay;
  312 + downloadValues.durationHour = plotValues.durationHour;
  313 + downloadValues.durationMin = plotValues.durationMin;
  314 + downloadValues.durationSec = plotValues.durationSec;
  315 + if (plotValues.timeTables)
  316 + downloadValues.timeTables = plotValues.timeTables;
  317 + downloadValues.list = [];
  318 + plotNode.get('object').panels().each(function (panel) {
  319 + panel.params().each(function (param) {
  320 + paramObj = param.getJsonValues();
  321 + paramObj.id = "";
  322 + downloadValues.list.push(paramObj);
  323 + });
  324 + });
  325 + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.download.id, true, function (module) {
  326 + module.editFromJsonData(downloadValues);
  327 + });
303 328 }
304 329 });
... ...
js/app/models/BkgJobNode.js
... ... @@ -395,97 +395,5 @@ Ext.define(&#39;amdaModel.BkgJobNode&#39;, {
395 395 this.set('rootNode',this.myGetOwnerTree().getRootNode().findChild( 'id', rootNodeId, true));
396 396 }
397 397 return this.get('rootNode');
398   - },
399   -
400   - /**
401   - * @override amdaModel.ExecutableNode.execute PNG (interactive session only!!!)
402   - */
403   - execute : function(arguments)
404   - {
405   - // Not needed to send the whole request
406   - // var jsonObj = this.get('object').getJsonValues(true);
407   - //TODO append jsonObj.action at server side => history!!!
408   - var jsonObj = {};
409   - var isMulti = arguments[0];
410   - jsonObj.action = {name:arguments[1],arg1:arguments[2],arg2:arguments[3]};
411   - //AKKA replace resultID by folderId
412   - jsonObj.folderId = this.get('object').get('folderId');
413   - //jsonObj.resultId = this.get('object').get('resultFolder');
414   -
415   - this.action = jsonObj.action.name;
416   -
417   - // this.set('tabId', jsonObj.tabId);
418   -
419   - // Node exists already, interactive Session
420   - var isInteractive = true;
421   - var isNewTab = false;
422   -
423   - loadMask.show(this.get('object').get('tabId'));
424   - AmdaAction.execute({nodeType : this.get('nodeType')}, jsonObj, function(res,e)
425   - {
426   - loadMask.hide();
427   - //AKKA - Rework of the result treatment for the integration with the new kernel
428   - if (!e.status)
429   - {
430   - myDesktopApp.errorMsg('Internal error during request');
431   - return;
432   - }
433   - if (!res.success)
434   - {
435   - myDesktopApp.errorMsg(res.message);
436   - return;
437   - }
438   - // NO background jobs for PNG !!!!! Timeout KILL
439   - if (res.status == amdaModel.BkgJobNode.STATUS_LIST.DONE)
440   - {
441   - this.updateNode(res);
442   - this.updateObject(res);
443   - this.editNode(isNewTab, isInteractive);
444   - }
445   - else
446   - {
447   - myDesktopApp.warningMsg(res.message);
448   - // keep this for case of Background Job
449   - /* var id = res.id;
450   - var text = 'job_' + res.pid;
451   - var status = amdaModel.BkgJobNode.STATUS_LIST.IN_PROGRESS;
452   - var newobj = Ext.create('amdaModel.Plot',
453   - { resultId : id, name : res.rawname, resultId: res.rawname});
454   - var newNode = Ext.create(this.$className, { id : id, pid : res.pid, text : text, jobType : 'request',
455   - leaf : true, status : status, rawname : res.rawname, object : newobj});
456   - newNode.createJobNode(false);
457   - */
458   - }
459   - }, this);
460   - },
461   -
462   - updateNode : function(res)
463   - {
464   - var windowId = 'plot' + this.get('tabId')+'-win';
465   - var win = myDesktopApp.getDesktop().getWindow(windowId);
466   - //TODO if it is possible to close window before getting result?
467   - if (!win)
468   - myDesktopApp.errorMsg('You have closed window!!!');
469   - else
470   - {
471   - var panelResult = win.items.items[0];
472   - panelResult.setObjectIntoNode();
473   - }
474   - },
475   -
476   - updateObject : function(res)
477   - {
478   - var object = this.get('object');
479   - object.set('outputName', res.name);
480   - object.set('resultId', res.result);
481   - object.set('startDate', res.startDate);
482   - object.set('stopDate', res.stopDate);
483   -
484   - if (object.get('timesrc') == amdaModel.AmdaTimeObject.inputTimeSrc[0] && this.action != 'zoom')
485   - {
486   - object.set('intervalN', res.intervalN);
487   - object.set('totalN', res.totalN);
488   - object.set('ttName', res.tableName);
489   - }
490   - }
  398 + }
491 399 });
... ...
js/app/models/Download.js
... ... @@ -7,30 +7,129 @@
7 7 * @author myriam
8 8 * @version $Id: Download.js 2068 2014-02-06 11:27:38Z elena $
9 9 */
10   -
  10 +
  11 +
  12 +Ext.define('amdaModel.DownloadConfig', {
  13 + singleton: true,
  14 +
  15 + defaultValues : {
  16 + timeformat: 'YYYY-MM-DDThh:mm:ss',
  17 + timeformatTT: 'YYYY-MM-DDThh:mm:ss',
  18 + fileformat: 'ASCII',
  19 + fileformatTT: 'text',
  20 + filecompress: 'tar+gzip',
  21 + filecompressTT: 'tar+gzip',
  22 + filestructure: '2'
  23 + },
  24 +
  25 + timeformatData: [
  26 + ['YYYY-MM-DDThh:mm:ss', 'YYYY-MM-DDThh:mm:ss.ms', 'ISO format with msecs'],
  27 + ['DD Time', 'YYYYDOYhhmmssms', 'Day-Of-Year, 1 Jan : DOY = 0'],
  28 + ['Timestamp', 'Seconds from 1970', 'Total of seconds from the Unix Epoch on January 1st, 1970 at UTC.'],
  29 + ['YYYY MM DD hh mm ss', 'YYYY MM DD hh mm ss ms', 'date with spaces'],
  30 + ['Timestamp-with-milliseconds', 'Seconds from 1970 with ms', 'Total of seconds from the Unix Epoch with milliseconds.']
  31 + ],
  32 + fileformatData: [
  33 + ['ASCII', 'ASCII'],
  34 + ['vot', 'VOTable'],
  35 + ['cdf', 'CDF'],
  36 + ['json', 'JSON']
  37 + ],
  38 + fileformatTTData: [
  39 + ['text', 'plain text'],
  40 + ['vot', 'VOTable']
  41 + ],
  42 + filecompressData: [
  43 + ['zip', 'zip'],
  44 + ['tar+gzip', 'tar+gzip']
  45 + ],
  46 + filecompressTTData: [
  47 + ['zip', 'zip'],
  48 + ['tar+gzip', 'tar+gzip'],
  49 + ['none', 'none']
  50 + ],
  51 + filestructureData: [
  52 + ['0', 'All In One File'],
  53 + ['1', 'One File Per Time Interval'],
  54 + ['2', 'One File Per Param/Interval']
  55 + ]
  56 +});
11 57  
12 58 Ext.define('amdaModel.Download', {
13 59 extend: 'amdaModel.AmdaTimeObject',
14   -
  60 +
  61 + requires: [
  62 + "amdaModel.DownloadParam"
  63 + ],
  64 +
15 65 fields : [
16 66 {name: 'type', type: 'string', defaultValue: 'Download'},
17 67 {name: 'downloadSrc', type: 'string'},
18   - {name: 'list', defaultValue: null }, // array of parameters
19   - {name: 'timeformat', type: 'string'},
20   - {name: 'timeformatTT', type: 'string'},
21   - {name: 'structure', type: 'string'},
  68 + {name: 'timeformat', type: 'string', defaultValue: amdaModel.DownloadConfig.defaultValues.timeformat},
  69 + {name: 'timeformatTT', type: 'string', defaultValue: amdaModel.DownloadConfig.defaultValues.timeformatTT},
  70 + {name: 'filestructure', type: 'string', defaultValue: amdaModel.DownloadConfig.defaultValues.filestructure},
22 71 {name: 'refparamSampling', type: 'boolean', defaultValue: false},
23 72 {name: 'separateInfoFile', type: 'boolean', defaultValue: false},
24   - {name: 'sampling', type: 'int', defaultValue: '600'},
  73 + {name: 'sampling', type: 'float', defaultValue: '600'},
25 74 {name: 'scientificformat', type: 'boolean', defaultValue: true},
26 75 {name: 'fileprefix', type: 'string'},
27   - {name: 'fileformat', type: 'string'},
28   - {name: 'fileformatTT', type: 'string'},
29   - {name: 'compression', type: 'string'},
30   - {name: 'compressionTT', type: 'string'}
  76 + {name: 'fileformat', type: 'string', defaultValue: amdaModel.DownloadConfig.defaultValues.fileformat},
  77 + {name: 'fileformatTT', type: 'string', defaultValue: amdaModel.DownloadConfig.defaultValues.fileformatTT},
  78 + {name: 'compression', type: 'string', defaultValue: amdaModel.DownloadConfig.defaultValues.filecompress},
  79 + {name: 'compressionTT', type: 'string', defaultValue: amdaModel.DownloadConfig.defaultValues.filecompressTT}
  80 + ],
  81 +
  82 + associations : [
  83 + {
  84 + type : 'hasMany',
  85 + model : 'amdaModel.DownloadParam',
  86 + name : 'params'
  87 + }
31 88 ],
32 89  
33   - propertiesToCopy : 'id,name,downloadSrc,refparamSampling,separateInfoFile,sampling,scientificformat,list,timeformat,timeformatTT,structure,fileprefix,fileformat,fileformatTT,compression,compressionTT',
  90 + propertiesToCopy : 'id,name,downloadSrc,refparamSampling,separateInfoFile,sampling,scientificformat,list,timeformat,timeformatTT,filestructure,fileprefix,fileformat,fileformatTT,compression,compressionTT',
  91 +
  92 + constructor: function(){
  93 + var me = this;
  94 + me.callParent(arguments);
  95 + if ((arguments.length > 0) && arguments[0])
  96 + {
  97 + if (arguments[0].list)
  98 + me.loadParams(arguments[0].list);
  99 + }
  100 + this.dirty = false;
  101 + },
  102 +
  103 + loadParams: function(params)
  104 + {
  105 + /* Compatability mode */
  106 + Ext.each(params, function(param, index) {
  107 + if (param.hasOwnProperty('is-init')) {
  108 + return;
  109 + }
  110 + params[index]['dim1-sum-type'] = param['dim1-is-range'] ? 1 : 0;
  111 + params[index]['dim1-min-value'] = param['dim1-min-range'];
  112 + params[index]['dim1-max-value'] = param['dim1-max-range'];
  113 + params[index]['dim2-sum-type'] = param['dim2-is-range'] ? 1 : 0;
  114 + params[index]['dim2-min-value'] = param['dim2-min-range'];
  115 + params[index]['dim2-max-value'] = param['dim2-max-range'];
  116 + params[index]['is-init'] = true;
  117 + });
  118 + this.params().loadData(params);
  119 + },
  120 +
  121 + isDirty : function() {
  122 + if (this.dirty)
  123 + return true;
  124 +
  125 + var d = false;
  126 +
  127 + this.params().each(function (param, index) {
  128 + if (param.dirty)
  129 + d = true;
  130 + });
  131 + return d;
  132 + },
34 133  
35 134 getJsonValues : function(){
36 135  
... ... @@ -38,9 +137,10 @@ Ext.define(&#39;amdaModel.Download&#39;, {
38 137 myValues.nodeType = 'download';//amdaModel.DownloadNode.nodeType;
39 138 myValues.type = this.get('type');
40 139 myValues.downloadSrc = this.get('downloadSrc');
  140 + myValues.name = this.get('name');
41 141 //Data download
42 142 if (myValues.downloadSrc === '0') { // Data download
43   - myValues.structure = this.get('structure');
  143 + myValues.filestructure = this.get('filestructure');
44 144 myValues.refparamSampling = this.get('refparamSampling');
45 145 myValues.separateInfoFile = this.get('separateInfoFile');
46 146 myValues.scientificformat = this.get('scientificformat');
... ... @@ -74,13 +174,10 @@ Ext.define(&#39;amdaModel.Download&#39;, {
74 174 }
75 175  
76 176 // if there's at least one parameter
77   - if (this.get('list') && this.get('list').length) {
78   - var list = this.get('list');
79   - myValues.list=[];
80   - Ext.each(list, function(item, index){
81   - myValues.list[index] = item.getJsonValues();
82   - });
83   - }
  177 + myValues.list = []
  178 + this.params().each(function (param, index) {
  179 + myValues.list[index] = param.getJsonValues();
  180 + });
84 181 myValues.fileformat = this.get('fileformat');
85 182 myValues.timeformat = this.get('timeformat');
86 183 myValues.compression = this.get('compression');
... ...
js/app/models/DownloadNode.js
... ... @@ -2,7 +2,7 @@
2 2 * Project : AMDA-NG4
3 3 * Name : DownloadNode.js
4 4 * @class amdaModel.DownloadNode
5   - * @extends Ext.data.Model
  5 + * @extends amdaModel.ExecutableNode
6 6 * @brief Basic Model of Node corresponding to a download request
7 7 * @author Myriam
8 8 * @version $Id: DownloadNode.js 2949 2015-06-23 10:25:59Z elena $
... ... @@ -10,70 +10,24 @@
10 10  
11 11 Ext.define('amdaModel.DownloadNode', {
12 12  
13   - extend: 'Ext.data.Model',
14   - singleton: true,
  13 + extend: 'amdaModel.ExecutableNode',
  14 +
  15 + statics: {
  16 + nodeType: 'download',
  17 + objectName: 'Download'
  18 + },
15 19  
16   - fields:[{name : 'downloadType', type : 'string'},
17   - {name: 'object', type: 'object'},
18   - {name: 'realLinkedNode', type: 'amdaModel.AmdaNode'},
19   - {name: 'moduleId', type: 'string', defaultValue:'down-win'},
20   - {name: 'nodeType', type: 'string', defaultValue: 'download'},
21   - {name: 'objectDataModel', type: 'string', defaultValue:'amdaModel.Download'},
22   - {name: 'jobNode', type: 'string', defaultValue: 'amdaModel.BkgJobNode'}
23   - ],
24   -
25   - isExecutable: function(){
26   - return true;
27   - },
28   -
29   - getObjectCallback : function(result,remoteEvent){
30   - var t = remoteEvent.getTransaction();
31   - if (result) {
32   - var paramObj = Ext.create(this.get('objectDataModel'), result);
33   - // set parameter into node
34   - this.set('object', paramObj);
35   - var downObject = amdaModel.DownloadNode.decodeObject();
36   - // Edition ;
37   - amdaModel.DownloadNode.set('object',Ext.create('amdaModel.Download',downObject));
38   - amdaModel.DownloadNode.editInModule();
39   - }
40   - else {
41   - myDesktopApp.errorMsg(t.action + "." + t.method + " : No parameter '"
42   - +this.get('name')+"' found!");
43   - // EXCEPTION : parameter not found !?
44   - }
45   - },
46   -
47   - editInModule : function () {
48   - var me = this;
49   - myDesktopApp.getLoadedModule(this.get('moduleId'), true, function (module) {
50   - // If the node to edit is not already linked to this module
51   - if (module.getLinkedNode() != me) {
52   - // set relative node into parameter Module
53   - module.setLinkedNode(me);
54   - }
55   - else {// the node to edit is already edited
56   - //TODO: TBD : message to user
57   - //Sol1: msg alert: "warning this node is already edited! If you want to get the original, please press the 'reset' button"->'OK'
58   - //Sol2: msg with user choice: "warning this node is already edited! Would you confirm this action and lost your modification?"->'Confirm','Cancel'
59   - }
60   - // Opening parameter window
61   - module.createWindow();
62   - });
63   - },
  20 + constructor : function(config) {
  21 + this.callParent(arguments);
  22 + this.set('moduleId',myDesktopApp.dynamicModules.download.id);
  23 + this.set('objectDataModel',amdaModel.Download.$className);
  24 + },
64 25  
65 26 decodeObject: function(obj) {
66 27 var myValues = new Object();
67 28 myValues.list=[];
68 29  
69   - if (!obj) {
70   - var fullObject = this.get('realLinkedNode').get('object');
71   - }
72   - else {
73   - var fullObject = obj;
74   - }
75   -
76   - fullObject.panels().each(function (panel) {
  30 + obj.panels().each(function (panel) {
77 31 panel.params().each(function (param) {
78 32 var myParam = new Object();
79 33 myParam.paramid = param.get('paramid');
... ... @@ -98,13 +52,13 @@ Ext.define(&#39;amdaModel.DownloadNode&#39;, {
98 52 alert('Parameter '+ myParam.paramid + ' is PlotOnly');
99 53 });
100 54 });
101   - myValues.timesrc = fullObject.get('timesrc');
  55 + myValues.timesrc = obj.get('timesrc');
102 56 // if there's at least one timeTable name into 'timeTables' collection
103 57 if (myValues.timesrc == amdaModel.AmdaTimeObject.inputTimeSrc[0]
104   - && fullObject.get('timeTables')
105   - && fullObject.get('timeTables').length){
  58 + && obj.get('timeTables')
  59 + && obj.get('timeTables').length){
106 60 // get complete timeTables collection
107   - var timeTables = fullObject.get('timeTables');
  61 + var timeTables = obj.get('timeTables');
108 62 // init an empty array for timeTables
109 63 myValues.timeTables=[];
110 64 // for each interval record
... ... @@ -119,150 +73,15 @@ Ext.define(&#39;amdaModel.DownloadNode&#39;, {
119 73 });
120 74 }
121 75 else {
122   - myValues.startDate = fullObject.get('startDate');
123   - myValues.stopDate = fullObject.get('stopDate');
124   - myValues.durationDay = fullObject.get('durationDay');
125   - myValues.durationHour = fullObject.get('durationHour');
126   - myValues.durationMin = fullObject.get('durationMin');
127   - myValues.durationSec = fullObject.get('durationSec');
  76 + myValues.startDate = obj.get('startDate');
  77 + myValues.stopDate = obj.get('stopDate');
  78 + myValues.durationDay = obj.get('durationDay');
  79 + myValues.durationHour = obj.get('durationHour');
  80 + myValues.durationMin = obj.get('durationMin');
  81 + myValues.durationSec = obj.get('durationSec');
128 82 }
129 83  
130   - myValues.name = fullObject.get('name');
  84 + myValues.name = obj.get('name');
131 85 return myValues;
132   - },
133   -
134   - encodeObject: function() {
135   - },
136   -
137   - loadJobTree : function(sendToSamp, clientId) {
138   - //TBD - BRE - fix code duplication with ExecutableNode if possible
139   - var rootNode = Ext.getCmp(amdaUI.ExplorerUI.JOB_TAB.TREE_ID).getRootNode();
140   - var me = this;
141   - amdaModel.InteractiveNode.preloadNodes(rootNode,
142   - function()
143   - {
144   - amdaModel.InteractiveNode.jobTreeLoaded = true;
145   - me.realExecute(sendToSamp, clientId);
146   - });
147   - },
148   -
149   - execute : function(sendToSamp, clientId) {
150   -
151   - if (!amdaModel.ExecutableNode.jobTreeLoaded) this.loadJobTree(sendToSamp, clientId);
152   - else this.realExecute(sendToSamp, clientId);
153   - },
154   -
155   -/**
156   -* Method to execute this node
157   -*/
158   - realExecute : function(sendToSamp, clientId) {
159   - var jsonObject = this.get('object').getJsonValues();
160   - if (!jsonObject.list && !jsonObject.images) {
161   - myDesktopApp.warningMsg('Please select at least one Parameter (Get Data) or one Time Table (Get Time Table)');
162   - return;
163   - }
164   -
165   - if (sendToSamp) {
166   - jsonObject.sendToSamp = true;
167   - }
168   -
169   - loadMask.show();
170   - AmdaAction.execute({nodeType : this.get('nodeType')}, jsonObject, function(res,e)
171   - {
172   - loadMask.hide();
173   -
174   - //AKKA - Rework of the result treatment for the integration with the new kernel
175   - if (!e.status)
176   - {
177   - myDesktopApp.errorMsg('Internal error during download request');
178   - return;
179   - }
180   -
181   - if (!res.success)
182   - {
183   - myDesktopApp.errorMsg(res.message);
184   - return;
185   - }
186   - //TBD if such condition is OK ?
187   - if (!res.id && res.download) {
188   - if (res.sendToSamp) {
189   - myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.interop.id, true, function (module) {
190   - Ext.Array.each(res.download, function(download) {
191   - module.sendVOTable(download, clientId ? clientId : 'hub');
192   - });
193   - });
194   - return;
195   - } else if (res.compression) {
196   - window.location.href = res.download;
197   - }
198   - else {
199   - window.open(res.download, '_blank');
200   - }
201   - return;
202   - }
203   -
204   - if (logExecTime && res.exectime && (res.exectime != 0)) {
205   - console.log("CMD EXEC TIME FOR "+res.id+" = "+res.exectime+"ms");
206   - }
207   -
208   - var newobj = this.createJobObject(res);
209   - var newNode = Ext.create(this.get('jobNode'),
210   - {
211   - id : res.id,
212   - info : res.info,
213   - jobType : this.get('nodeType'),
214   - processId : res.id,
215   - text : res.name,
216   - status : res.status,
217   - stop : res.stop,
218   - leaf : true,
219   - object : newobj
220   -
221   - });
222   -
223   - // new Tab
224   - switch (res.status)
225   - {
226   - case amdaModel.BkgJobNode.STATUS_LIST.DONE :
227   - if (!res.sendToSamp) {
228   - // New tab, non-interactive session
229   - var isInteractive = false;
230   - var isNewTab = true;
231   - newNode.createJobNode(true);
232   - newNode.editNode(isNewTab, isInteractive);
233   - }
234   - else {
235   - var files = res.result.split(",");
236   - Ext.each(files, function(file) {
237   - var href = 'data/'+sessionID+'/RES/'+ res.folder + '/' + file;
238   - myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.interop.id, true, function (module) {
239   - module.sendVOTable(href, clientId ? clientId : 'hub');
240   - });
241   - });
242   - }
243   - break;
244   - case amdaModel.BkgJobNode.STATUS_LIST.IN_PROGRESS :
245   - newNode.createJobNode(false);
246   - break;
247   - default:
248   - newNode.createJobNode(true);
249   - }
250   - }, this );
251   - },
252   -
253   - createJobObject: function(res) {
254   -
255   - var obj = this.get('object').getJsonValues();
256   - //TODO text, name, outputName - if all is needed
257   - //new object to attach to new bkgJobNode
258   - //TODO Ext.clone()
259   -
260   - var newobj = Ext.copyTo({}, obj, this.get('object').propertiesToCopy);
261   - newobj.id = res.id;
262   - newobj.resultId = res.result;
263   - newobj.folderId = res.folder;
264   - newobj = Ext.create(this.get('object').$className, newobj);
265   -
266   - return newobj;
267   - }
  86 + }
268 87 });
... ...
js/app/models/ExecutableNode.js
... ... @@ -22,35 +22,41 @@ Ext.define(&#39;amdaModel.ExecutableNode&#39;, {
22 22 this.set('jobNode', 'amdaModel.BkgJobNode');
23 23 },
24 24  
25   - loadJobTree : function()
  25 + loadJobTree : function(opts)
26 26 {
27 27 var rootNode = Ext.getCmp(amdaUI.ExplorerUI.JOB_TAB.TREE_ID).getRootNode();
28 28 var me = this;
29 29 amdaModel.InteractiveNode.preloadNodes(rootNode, function(){
30 30 amdaModel.ExecutableNode.jobTreeLoaded = true;
31   - me.realExecute();
  31 + me.realExecute(opts);
32 32 });
33 33 },
34 34  
35   - execute : function(isDirty)
  35 + execute : function(opts)
36 36 {
37 37 if (!amdaModel.ExecutableNode.jobTreeLoaded)
38   - this.loadJobTree();
  38 + this.loadJobTree(opts);
39 39 else
40   - this.realExecute();
  40 + this.realExecute(opts);
41 41 },
42 42  
43 43 /**
44 44 * Method to execute this node
45 45 */
46   - realExecute : function()
  46 + realExecute : function(opts)
47 47 {
48 48 var isInteractivePlot = (this.get('nodeType') == 'request') && (this.get('object').get('file-output') == 'INTERACTIVE') || (this.get('nodeType') == 'multiplot');
  49 +
  50 + var jsonObject = this.get('object').getJsonValues();
  51 + if (opts && opts.sendToSamp) {
  52 + jsonObject.sendToSamp = true;
  53 + opts.clientId = opts.clientId ? opts.clientId : 'hub';
  54 + }
49 55  
50 56 if (!loadMask.isMasked())
51 57 loadMask.show(isInteractivePlot);
52 58  
53   - AmdaAction.execute({nodeType : this.get('nodeType')}, this.get('object').getJsonValues(true),
  59 + AmdaAction.execute({nodeType : this.get('nodeType')}, jsonObject,
54 60 function(res,e)
55 61 {
56 62 loadMask.hide();
... ... @@ -74,7 +80,36 @@ Ext.define(&#39;amdaModel.ExecutableNode&#39;, {
74 80 module.updateInteractiveSession(res, true);
75 81 });
76 82 }
  83 + else if (!res.id && res.download) {
  84 + //Download TT / Cat
  85 + if (res.sendToSamp) {
  86 + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.interop.id, true, function (module) {
  87 + Ext.Array.each(res.download, function(download) {
  88 + module.sendVOTable(download, opts.clientId);
  89 + });
  90 + });
  91 + return;
  92 + } else if (res.compression) {
  93 + window.location.href = res.download;
  94 + }
  95 + else {
  96 + window.open(res.download, '_blank');
  97 + }
  98 + return;
  99 + }
77 100 else {
  101 + if (res.sendToSamp) {
  102 + // Send to SAMP from Download UI
  103 + var files = res.result.split(",");
  104 + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.interop.id, true, function (module) {
  105 + Ext.each(files, function(file) {
  106 + var href = 'data/'+sessionID+'/RES/'+ res.folder + '/' + file;
  107 + module.sendVOTable(href, opts.clientId);
  108 + });
  109 + });
  110 + return;
  111 + }
  112 +
78 113 if (logExecTime && res.exectime && (res.exectime != 0)) {
79 114 console.log("CMD EXEC TIME FOR "+res.id+" = "+res.exectime+"ms");
80 115 }
... ... @@ -96,7 +131,7 @@ Ext.define(&#39;amdaModel.ExecutableNode&#39;, {
96 131  
97 132 newNode.get('object').on('execute', function() {
98 133 // Then call the node creation method
99   - this.execute(arguments);
  134 + this.execute(opts);
100 135 }, newNode);
101 136  
102 137 switch (res.status)
... ...
js/app/models/InteractiveNode.js
... ... @@ -487,78 +487,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
487 487 createDownload: function(node)
488 488 {
489 489 myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.download.id, true, function (module) {
490   - if (!myDesktopApp.desktop.getWindow(myDesktopApp.dynamicModules.download.id)) {
491   - var request = Ext.create(amdaModel.Download.$className);
492   - amdaModel.DownloadNode.set('object',request);
493   - // singleton!
494   - amdaModel.DownloadNode.editInModule();
495   - if ((node.get('globalStart') != null) && (node.get('globalStop') != null) && node.get('globalStart') != 'depending on mission' && node.get('isParameter')) {
496   - module.getUiContent().setTimeFromData(node.getTimeFromNode(node));
497   - }
498   - }
499   - var paramName;
500   - var components = null;
501   - switch (node.$className) {
502   - case 'amdaModel.AliasNode' :
503   - paramName = "#"+node.get('text');
504   - break;
505   - case 'amdaModel.DerivedParamComponentNode' :
506   -
507   - paramId = node.get('text');
508   - var parentId = paramId.substr(0, paramId.length - 3);
509   - paramName= "ws_" + parentId;
510   - var regExp = /\(([\d]+)\)/;
511   - var component_index = regExp.exec(paramId);
512   - if (component_index)
513   - {
514   - components = [];
515   - components['index1'] = component_index[1];
516   - }
517   - break;
518   - case 'amdaModel.MyDataParamComponentNode' :
519   - paramId = node.get('text');
520   - var parentId = paramId.substr(0, paramId.length - 3);
521   - paramName= "wsd_" + parentId;
522   - var regExp = /\(([\d]+)\)/;
523   - var component_index = regExp.exec(paramId);
524   - if (component_index)
525   - {
526   - components = [];
527   - components['index1'] = component_index[1];
528   - }
529   - break;
530   - case 'amdaModel.DerivedParamNode' :
531   - paramName = "ws_"+node.get('text');
532   - break;
533   - case 'amdaModel.MyDataParamNode' :
534   - paramName = 'wsd_'+node.get('text');
535   - break;
536   - default :
537   - if (node.get('alias')!= "" )
538   - paramName = "#"+node.get('alias');
539   - else
540   - paramName = node.get('id');
541   - }
542   - var component_info = node.get('component_info');
543   - var predefinedArgs = node.get('predefinedArgs');
544   - if (component_info && component_info.parentId) {
545   - //It's a component
546   - paramName = component_info.parentId;
547   - components = [];
548   - if (component_info.index1)
549   - components['index1'] = component_info.index1;
550   - if (component_info.index2)
551   - components['index2'] = component_info.index2;
552   - predefinedArgs = node.parentNode.get('predefinedArgs');
553   - }
554   - if (predefinedArgs) {
555   - module.parseTemplatedParam(paramName, function(param_info) {
556   - module.addParam(param_info.paramid, true, node.get('needsArgs'), components, param_info.template_args);
557   - });
558   - }
559   - else {
560   - module.addParam(paramName,true,node.get('needsArgs'),components);
561   - }
  490 + module.addParameter(node);
562 491 });
563 492 },
564 493  
... ...
js/app/models/PlotObjects/PlotPanelObject.js
... ... @@ -605,7 +605,7 @@ Ext.define(&#39;amdaPlotObj.PlotPanelObject&#39;, {
605 605 break;
606 606 case 'xyPlot' :
607 607 if (this.get('panel-scatter-isotropic'))
608   - info += ', Isotropic';
  608 + info += ', Orthonormal';
609 609 break;
610 610 }
611 611 return info;
... ...
js/app/models/Search.js
... ... @@ -21,7 +21,7 @@ Ext.define(&#39;amdaModel.Search&#39;, {
21 21  
22 22 fields : [
23 23 // {name: 'name', type: 'string', defaultValue: 'Search'},
24   - {name: 'sampling', type: 'int', defaultValue: '600'},
  24 + {name: 'sampling', type: 'float', defaultValue: '600'},
25 25 {name: 'gap', type: 'int', defaultValue: '5'},
26 26 {name: 'description', type: 'string'},
27 27 {name: 'expression', type: 'string'},
... ...
js/app/models/StatisticsNode.js
... ... @@ -14,9 +14,7 @@ Ext.define(&#39;amdaModel.StatisticsNode&#39;, {
14 14 singleton: true,
15 15  
16 16 fields: [
17   - {name: 'downloadType', type : 'string'},
18 17 {name: 'object', type: 'object'},
19   - {name: 'realLinkedNode', type: 'amdaModel.AmdaNode'},
20 18 {name: 'moduleId', type: 'string', defaultValue:'statistics-win'},
21 19 {name: 'nodeType', type: 'string', defaultValue: 'statistics'},
22 20 {name: 'objectDataModel', type: 'string', defaultValue:'amdaModel.Stats'},
... ...
js/app/stores/AmdaTreeReader.js
... ... @@ -77,4 +77,4 @@ Ext.define(&#39;amdaReader.AmdaTreeReader&#39;, {
77 77 * @abstract This method has to be overriden in subclasses
78 78 */
79 79 getType: function(node){}
80   -});
81 80 \ No newline at end of file
  81 +});
... ...
js/app/stores/ExplorerReader.js
... ... @@ -46,7 +46,9 @@ Ext.define(&#39;amdaReader.ExplorerReader&#39;, {
46 46 case 'condition' :
47 47 return amdaModel.SearchNode;
48 48 case 'request' :
49   - return amdaModel.PlotNode;
  49 + return amdaModel.PlotNode;
  50 + case 'download' :
  51 + return amdaModel.DownloadNode;
50 52 case 'bkgWorks' :
51 53 return amdaModel.BkgJobNode;
52 54 default:
... ... @@ -56,4 +58,4 @@ Ext.define(&#39;amdaReader.ExplorerReader&#39;, {
56 58  
57 59  
58 60 }
59   -});
60 61 \ No newline at end of file
  62 +});
... ...
js/app/views/AstroImagesUI.js
... ... @@ -38,7 +38,8 @@ Ext.define(&#39;amdaUI.AstroImagesUI&#39;, {
38 38 extend: 'Ext.form.Panel',
39 39  
40 40 requires: [
41   - 'amdaUI.SendToSampButtonUI'
  41 + 'amdaUI.SendToSampButtonUI',
  42 + 'amdaModel.DownloadNode'
42 43 ],
43 44  
44 45 //
... ... @@ -318,9 +319,13 @@ Ext.define(&#39;amdaUI.AstroImagesUI&#39;, {
318 319 obj.set('compression','zip');
319 320 obj.set('list',imageList);
320 321 obj.set('downloadSrc',2);
321   -
322   - amdaModel.DownloadNode.set('object',obj);
323   - amdaModel.DownloadNode.execute();
  322 +
  323 + var downloadNode = Ext.create('amdaModel.DownloadNode', {
  324 + leaf : true,
  325 + });
  326 +
  327 + downloadNode.set('object',obj);
  328 + downloadNode.execute();
324 329 },
325 330  
326 331 getAdditionalRequestConfig : function(panelId)
... ...
js/app/views/CatalogUI.js
... ... @@ -126,13 +126,18 @@ Ext.define(&#39;amdaUI.CatalogUI&#39;, {
126 126 Ext.Msg.confirm('Generate TT', 'Current Catalog has been modified.\nDo you want to save it to include these changes in the generated Time Table ?',
127 127 function (btn, text) {
128 128 if (btn == 'yes') {
  129 + var me = this;
129 130 // mark this.closed as true before the call to close() as that will fire the beforeclose event again
130 131 if (this.object.get('id') == "") {
131 132 // case of creation of catalog
132   - this.saveCatalog(true, true);
  133 + this.saveCatalog(function () {
  134 + me.createTT(me.object.get('id'));
  135 + }, true);
133 136 } else {
134 137 // casse existing catalog
135   - this.saveProcess(false, true, true);
  138 + this.saveProcess(false, function () {
  139 + me.createTT(me.object.get('id'));
  140 + }, true);
136 141 }
137 142 return;
138 143 }
... ... @@ -534,6 +539,13 @@ Ext.define(&#39;amdaUI.CatalogUI&#39;, {
534 539 me.updateCount();
535 540 //Statistical plugin
536 541 this.fireEvent("refresh");
  542 + },
  543 + prefetch: function (store, records, successful, operation, eOpts) {
  544 + if (operation && (operation.action == 'read'))
  545 + {
  546 + if (operation.response && operation.response.result && operation.response.result.success)
  547 + me.status = operation.response.result.status;
  548 + }
537 549 }
538 550 }
539 551 });
... ... @@ -546,7 +558,11 @@ Ext.define(&#39;amdaUI.CatalogUI&#39;, {
546 558 me.TTGrid.getSelectionModel().deselectAll();
547 559 //
548 560 // // clear filters
549   - // me.TTGrid.getStore().clearFilter(true);
  561 + if (me.TTGrid.filters) {
  562 + me.TTGrid.getStore().clearFilter(true);
  563 + me.TTGrid.filters.clearFilters();
  564 + }
  565 +
550 566 //
551 567 // clear sort
552 568 me.TTGrid.getStore().sorters.clear();
... ... @@ -622,11 +638,11 @@ Ext.define(&#39;amdaUI.CatalogUI&#39;, {
622 638 this.object = obj;
623 639 module.linkedNode.create({notDisplayMsg: notDisplayMsg, callback: function () {
624 640 if (onAfterSave)
625   - this.createTT(this.object.get('id'));
  641 + onAfterSave();
626 642 }, scope: this});
627 643 }
628 644 // if the name has been modified this is a creation
629   - else if (this.fclose()) {
  645 + else if (this.fclose() || this.status && (this.status.nbFiltered > 0)) {
630 646 if (this.object.isModified('name') || this.object.get('fromPlugin')) {
631 647 // if object already has an id : it's a 'rename' of an existing
632 648 if (this.object.get('id')) {
... ... @@ -648,14 +664,14 @@ Ext.define(&#39;amdaUI.CatalogUI&#39;, {
648 664 module.linkedNode.create({callback: function () {
649 665 module.linkedNode.update({notDisplayMsg: notDisplayMsg, callback: function () {
650 666 if (onAfterSave)
651   - this.createTT(this.object.get('id'));
  667 + onAfterSave();
652 668 }, scope: this}, "", notDisplayMsg);
653 669 }, scope: this});
654 670 } else {
655 671 //update
656 672 module.linkedNode.update({notDisplayMsg: notDisplayMsg, callback: function () {
657 673 if (onAfterSave)
658   - this.createTT(this.object.get('id'));
  674 + onAfterSave();
659 675 }, scope: this});
660 676 }
661 677 }
... ...
js/app/views/DownloadUI.js
... ... @@ -16,25 +16,11 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
16 16 'amdaUI.TimeSelectorUI',
17 17 'amdaUI.ParamArgumentsPlug',
18 18 'amdaUI.SendToSampButtonUI',
  19 + 'amdaModel.Download',
19 20 'amdaModel.DownloadParam',
20 21 'amdaModel.RequestParamObject'
21 22 ],
22 23  
23   - //Old kernel time formats
24   - //timeformatData : [['Y-m-dTH:i:s', 'YYYY-MM-DDThh:mm:ss'], ['Y m d H i s', 'YYYY MM DD hh mm ss'], ['d m Y H i s', 'DD MM YYYY hh mm ss'], ['Y z H i s', 'YYYY DDD hh mm ss']],
25   - //New kernel time formats
26   - timeformatData: [['YYYY-MM-DDThh:mm:ss', 'YYYY-MM-DDThh:mm:ss.ms', 'ISO format with msecs'],
27   - ['DD Time', 'YYYYDOYhhmmssms', 'Day-Of-Year, 1 Jan : DOY = 0'],
28   - ['Timestamp', 'Seconds from 1970', 'Total of seconds from the Unix Epoch on January 1st, 1970 at UTC.'],
29   - ['YYYY MM DD hh mm ss', 'YYYY MM DD hh mm ss ms', 'date with spaces'],
30   - ['Timestamp-with-milliseconds', 'Seconds from 1970 with ms', 'Total of seconds from the Unix Epoch with milliseconds.']],
31   - timeformatTTData: [['Y-m-dTH:i:s', 'YYYY-MM-DDThh:mm:ss']],
32   - fileformatData: [['ASCII', 'ASCII'], ['vot', 'VOTable'], ['cdf', 'CDF'], ['json', 'JSON']],
33   - fileformatTTData: [['text', 'plain text'], ['vot', 'VOTable']],
34   - filecompressData: [['zip', 'zip'], ['tar+gzip', 'tar+gzip']],
35   - filecompressTT: [['zip', 'zip'], ['tar+gzip', 'tar+gzip'], ['none', 'none']],
36   - filestructureData: [['0', 'All In One File'], ['1', 'One File Per Time Interval'], ['2', 'One File Per Param/Interval']],
37   -
38 24 constructor: function (config) {
39 25 this.init(config);
40 26 this.callParent(arguments);
... ... @@ -47,6 +33,91 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
47 33 paramArgsPlug.onApply = this.onApplyParameterArgs;
48 34 },
49 35  
  36 + saveRequest: function()
  37 + {
  38 + var me = this;
  39 +
  40 + if (!this.updateObject()) {
  41 + return;
  42 + }
  43 +
  44 + var downloadModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.download.id);
  45 + if (!downloadModule) {
  46 + return;
  47 + }
  48 +
  49 + if ((this.object.get('id') != '') && (downloadModule.linkedNode.get('text') == this.object.get('name'))) {
  50 + this.saveProcess(false);
  51 + return;
  52 + }
  53 +
  54 + downloadModule.linkedNode.isValidName(this.fieldName.getValue(), function (res) {
  55 + if (!res)
  56 + {
  57 + me.fieldName.validFlag = 'Error during object validation';
  58 + myDesktopApp.errorMsg(me.fieldName.validFlag);
  59 + me.fieldName.validate();
  60 + return;
  61 + }
  62 +
  63 + if (!res.valid)
  64 + {
  65 + if (res.error)
  66 + {
  67 + if (res.error.search('subtree') != -1) {
  68 + Ext.MessageBox.show({title:'Warning',
  69 + msg: res.error+'<br/>Do you want to overwrite it?',
  70 + width: 300,
  71 + buttons: Ext.MessageBox.OKCANCEL,
  72 + fn : function(btn) {
  73 + if (btn == 'cancel') return;
  74 + this.fieldName.clearInvalid();
  75 + this.saveProcess(true);
  76 + },
  77 + icon: Ext.MessageBox.WARNING,
  78 + scope : me
  79 + });
  80 + me.fieldName.validFlag = true;
  81 + }
  82 + else
  83 + me.fieldName.validFlag = res.error;
  84 + }
  85 + else
  86 + {
  87 + me.fieldName.validFlag = 'Invalid object name';
  88 + myDesktopApp.errorMsg(me.fieldName.validFlag);
  89 + }
  90 + me.fieldName.validate();
  91 + return;
  92 + }
  93 +
  94 + me.fieldName.validFlag = true;
  95 + me.fieldName.validate();
  96 + me.saveProcess(false);
  97 + });
  98 + },
  99 +
  100 + saveProcess: function(toRename) {
  101 + var downloadModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.download.id);
  102 + if (this.object.isModified('name')) {
  103 + if (this.object.get('id'))
  104 + {
  105 + var contextNode = downloadModule.linkedNode.parentNode;
  106 + downloadModule.createLinkedNode();
  107 + downloadModule.linkedNode.set('contextNode',contextNode);
  108 + downloadModule.createObject(this.object.getJsonValues());
  109 + var downloadObj = downloadModule.linkedNode.get('object');
  110 + this.object = downloadObj;
  111 + if (toRename) downloadModule.linkedNode.toRename = true;
  112 + }
  113 + downloadModule.linkedNode.create();
  114 + }
  115 + else {
  116 + downloadModule.linkedNode.set('contextNode',downloadModule.contextNode);
  117 + downloadModule.linkedNode.update();
  118 + }
  119 + },
  120 +
50 121 addTT: function (newTTName, newTTid)
51 122 {
52 123 var tabPanel = this.formPanel.down();
... ... @@ -92,6 +163,14 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
92 163 this.timeSelector.intervalSel.updateDuration();
93 164 },
94 165  
  166 + addParameter: function(paramNode, updateTime)
  167 + {
  168 + if (this.doNotifyDrop(paramNode)) {
  169 + return this.doParamDrop(paramNode);
  170 + }
  171 + return false;
  172 + },
  173 +
95 174 addParam: function (paramId, isLeaf, needArgs, components, predefined_args)
96 175 {
97 176 // adding the parameter to the paramGrid
... ... @@ -123,44 +202,6 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
123 202 this.editParameterArgs(r);
124 203 },
125 204  
126   - addParams: function (arrayParams)
127   - {
128   - var arrayRec = new Array();
129   - var index = 1;
130   -
131   - if (arrayParams)
132   - {
133   - Ext.Array.each(arrayParams, function (item) {
134   - if (Ext.isObject(item)) {
135   - // handel case of derived parameters
136   - var patt_ws = new RegExp("ws_");
137   - var patt_wsd = new RegExp("wsd_");
138   - if (typeof paramId !== 'undefined' && ! patt_ws.test(item.paramid) && ! patt_wsd.test(item.paramid))
139   - {
140   - // for Parameter Name in Download Module
141   - var paramObj = amdaModel.RequestParamObject.getEmptyObj();
142   - paramObj.paramid = paramId;
143   - paramObj['dim1-index'] = item.get('dim1');
144   - paramObj['dim2-index'] = item.get('dim2');
145   -
146   - var r = Ext.create('amdaModel.DownloadParam', paramObj);
147   - } else
148   - {
149   - //for download from get Data in Plot module
150   - var r = Ext.create('amdaModel.DownloadParam', item);
151   - }
152   -
153   - } else {
154   - // for Download By Request in Operations menu
155   - //TODO BRE - Components selection
156   - var r = Ext.create('amdaModel.DownloadParam', {paramid: item});
157   - }
158   - arrayRec.push(r);
159   - });
160   - }
161   - this.paramGrid.getStore().loadData(arrayRec);
162   - },
163   -
164 205 // parameter name -> alias
165 206 updateConstruct: function (oldval, newval) {
166 207 var index = this.paramGrid.store.findExact('name', oldval);
... ... @@ -192,16 +233,16 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
192 233 {
193 234 var timeformat = values.timeformat;
194 235 var timeSource = this.timeSelector.getActiveTimeSource();
195   - var structure = values.filestructure;
  236 + var filestructure = values.filestructure;
196 237 var sampling = values.sampling ? values.sampling : 600;
197   - var refparamSampling = values.refparamsampling == 'on';
  238 + var refparamSampling = values.refparamSampling == 'on';
198 239 var fileprefix = values.fileprefix ? values.fileprefix : '';
199 240 var fileformat = values.fileformat;
200 241 var compression = values.compression;
201 242  
202 243 var fieldsWithoutName = basicForm.getFields().items;
203 244 Ext.Array.each(fieldsWithoutName, function (item, index, allItems) {
204   - if (!item.isValid()) {
  245 + if ((item.name != 'name') && !item.isValid()) {
205 246 if ((timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0]) &&
206 247 ((item.name == 'startDate') || (item.name == 'stopDate') || (item.name == 'duration'))) {
207 248 updateStatus = true;
... ... @@ -220,18 +261,23 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
220 261 updateStatus = false;
221 262 }
222 263  
  264 + if (updateStatus && (this.object.params().count() == 0))
  265 + {
  266 + myDesktopApp.warningMsg('You must define at least one parameter to download');
  267 + updateStatus = false;
  268 + }
  269 +
223 270 if (updateStatus)
224 271 {
225 272 /// real object update
226 273 // update TimeTable object with the content of form
227 274 basicForm.updateRecord(this.object);
  275 +
228 276 this.object.set('timesrc', timeSource);
229 277 // set valid intervals into TimeTable object
230 278 if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0])
231 279 this.object.set('timeTables', this.timeSelector.TTGrid.getStore().data.items);
232   - // set parameters
233   - this.object.set('list', this.paramGrid.getStore().data.items);
234   - this.object.set('structure', structure);
  280 + this.object.set('filestructure', filestructure);
235 281 this.object.set('refparamSampling', refparamSampling);
236 282 this.object.set('sampling', sampling);
237 283 this.object.set('fileprefix', fileprefix);
... ... @@ -246,7 +292,11 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
246 292 var timeformat = values.timeformatTT;
247 293 var compression = values.compressionTT;
248 294 var fileformat = values.fileformatTT;
249   - if (compression === 'none'
  295 + if (this.TTGrid.getStore().count() == 0) {
  296 + myDesktopApp.warningMsg('You must define at least one TimeTable or Catalog to download');
  297 + updateStatus = false;
  298 + }
  299 + else if (compression === 'none'
250 300 && this.TTGrid.getStore().count() > 1) {
251 301 myDesktopApp.warningMsg('You are going to download several time tables - select the Compression please');
252 302 updateStatus = false;
... ... @@ -266,31 +316,16 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
266 316 * load this.object into form
267 317 */
268 318 loadObject: function () {
269   -
270   - if (!this.object.get('timeformat'))
271   - this.object.set('timeformat', this.timeformatData[0][0]);
272   -
273   - if (!this.object.get('timeformatTT'))
274   - this.object.set('timeformatTT', this.timeformatData[0][0]);
275   -
276   - if (!this.object.get('fileformat'))
277   - this.object.set('fileformat', this.fileformatData[0][0]);
278   -
279   - if (!this.object.get('fileformatTT'))
280   - this.object.set('fileformatTT', this.fileformatTTData[0][0]);
281   -
282   - if (!this.object.get('compression'))
283   - this.object.set('compression', this.filecompressData[1][0]);
284   -
285   - if (!this.object.get('compressionTT'))
286   - this.object.set('compressionTT', this.filecompressData[1][0]);
287   -
288 319 // load object into form
289 320 this.formPanel.getForm().loadRecord(this.object);
290 321 // set object's TTs into the timeselector
291 322 this.addTTs(this.object.get('timeTables'));
292   - // set parameters
293   - this.addParams(this.object.get('list'));
  323 + // set parameters
  324 + this.paramGrid.reconfigure(this.object.params());
  325 + //this.paramGrid.getStore().loadData(this.object.params().data.items);
  326 + // select "Parameters" tab
  327 + var tabPanel = this.formPanel.down();
  328 + tabPanel.setActiveTab(0);
294 329 },
295 330  
296 331 /**
... ... @@ -299,7 +334,7 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
299 334 doDownload: function (sendToSamp, clientId) {
300 335 var downloadModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.download.id);
301 336 if (downloadModule)
302   - downloadModule.linkedNode.execute(sendToSamp, clientId);
  337 + downloadModule.linkedNode.execute({'sendToSamp': (sendToSamp == true), 'clientId': clientId});
303 338 },
304 339  
305 340 actionItem: function (grid, cell, cellIndex, record, row, recordIndex, e) {
... ... @@ -328,7 +363,7 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
328 363 if (!this.formPanel)
329 364 return;
330 365  
331   - var refParamCheck = this.formPanel.getForm().findField('refparamsampling');
  366 + var refParamCheck = this.formPanel.getForm().findField('refparamSampling');
332 367 var samplingField = this.formPanel.getForm().findField('sampling');
333 368  
334 369 if (samplingField && newValue !== oldValue) {
... ... @@ -355,12 +390,128 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
355 390 }
356 391 },
357 392  
  393 + doNotifyDrop: function(record)
  394 + {
  395 + if (record.get('nodeType') == 'localParam' && record.get('notyet'))
  396 + {
  397 + return false;
  398 + }
  399 + if (((record.get('nodeType') == 'localParam') ||
  400 + (record.get('nodeType') == 'remoteParam') ||
  401 + (record.get('nodeType') == 'remoteSimuParam') ||
  402 + (record.get('nodeType') == 'derivedParam') ||
  403 + (record.get('nodeType') == 'myDataParam') ||
  404 + (record.get('nodeType') == 'alias')) &&
  405 + (record.isLeaf() || record.get('isParameter')) &&
  406 + !record.get('disable'))
  407 + {
  408 + return true;
  409 + }
  410 +
  411 + return false;
  412 + },
  413 +
  414 + doParamDrop: function(record)
  415 + {
  416 + var idToSent;
  417 + var components = null;
  418 + var predefinedArgs = record.get('predefinedArgs');
  419 + switch (record.get('nodeType'))
  420 + {
  421 + case 'localParam' :
  422 + case 'remoteParam':
  423 + case 'remoteSimuParam':
  424 + idToSent = record.get('id');
  425 + if (record.get('alias') != "")
  426 + idToSent = "#" + record.get('alias');
  427 + var component_info = record.get('component_info');
  428 + if (component_info && component_info.parentId)
  429 + {
  430 + if (component_info.index1 || component_info.index2)
  431 + {
  432 + idToSent = component_info.parentId;
  433 + components = [];
  434 + if (component_info.index1)
  435 + components['index1'] = component_info.index1;
  436 + if (component_info.index2)
  437 + components['index2'] = component_info.index2;
  438 + predefinedArgs = record.parentNode.get('predefinedArgs');
  439 + }
  440 + if (record.get('needsArgs'))
  441 + {
  442 + idToSent = component_info.parentId;
  443 + if (component_info.index1)
  444 + {
  445 + components = [];
  446 + components['index1'] = component_info.index1;
  447 + }
  448 + }
  449 + }
  450 + break;
  451 + case 'alias' :
  452 + idToSent = "#" + record.get('text');
  453 + break;
  454 + case 'derivedParam' :
  455 + if (record.modelName == 'amdaModel.DerivedParamComponentNode')
  456 + {
  457 + paramId = record.get('text');
  458 + var parentId = paramId.substr(0, paramId.length - 3);
  459 + idToSent = "ws_" + parentId;
  460 + var regExp = /\(([\d]+)\)/;
  461 + var component_index = regExp.exec(paramId);
  462 + if (component_index)
  463 + {
  464 + components = [];
  465 + components['index1'] = component_index[1];
  466 + }
  467 + }
  468 + else {
  469 + idToSent = "ws_" + record.get('text');
  470 + }
  471 + break;
  472 + case 'myDataParam' :
  473 + if (record.modelName == 'amdaModel.MyDataParamComponentNode')
  474 + {
  475 + paramId = record.get('text');
  476 + var parentId = paramId.substr(0, paramId.length - 3);
  477 + idToSent = "wsd_" + parentId;
  478 + var regExp = /\(([\d]+)\)/;
  479 + var component_index = regExp.exec(paramId);
  480 + if (component_index)
  481 + {
  482 + components = [];
  483 + components['index1'] = component_index[1];
  484 + }
  485 + }
  486 + else {
  487 + idToSent = "wsd_" + record.get('text');
  488 + }
  489 + break;
  490 + default :
  491 + return false;
  492 + }
  493 +
  494 + var downModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.download.id);
  495 + if (downModule) {
  496 + if (predefinedArgs) {
  497 + downModule.parseTemplatedParam(idToSent, function(param_info) {
  498 + downModule.addParam(param_info.paramid, record.get('leaf'), record.get('needsArgs'), components, param_info.template_args);
  499 + });
  500 + }
  501 + else {
  502 + downModule.addParam(idToSent, record.get('leaf'), record.get('needsArgs'), components);
  503 + return true;
  504 + }
  505 + }
  506 + return true;
  507 + },
  508 +
358 509 /**
359 510 * Check if changes were made before closing window
360 511 * @return false
361 512 */
362 513 fclose: function () {
363   - return false;
  514 + return this.object.isDirty();
364 515 },
365 516  
366 517 init: function (config) {
... ... @@ -368,6 +519,23 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
368 519  
369 520 this.timeSelector = new amdaUI.TimeSelectorUI({id: 'downloadTimeSelector', flex: 1});
370 521  
  522 + this.fieldName = new Ext.form.field.Text({
  523 + labelAlign: 'left',
  524 + labelWidth: 90,
  525 + fieldLabel: 'Request Name',
  526 + name : 'name',
  527 + allowBlank : false,
  528 + stripCharsRe: /(^\s+|\s+$)/g,
  529 + validateOnChange: false,
  530 + validateOnBlur: false,
  531 + validFlag: false,
  532 + validator : function()
  533 + {
  534 + return this.validFlag;
  535 + }
  536 + });
  537 +
  538 + var downloadCont = this;
371 539 this.paramGrid = Ext.create('Ext.grid.Panel', {
372 540 flex: 2,
373 541 store: Ext.create('Ext.data.Store', {model: 'amdaModel.DownloadParam'}),
... ... @@ -401,129 +569,23 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
401 569 {
402 570 var me = this;
403 571 var el = me.body.dom;
404   - var dropTarget = Ext.create('Ext.dd.DropTarget', el, {
  572 + me.dropTarget = Ext.create('Ext.dd.DropTarget', el, {
405 573 ddGroup: 'explorerTree',
406 574 notifyEnter: function (ddSource, e, data) { },
407 575 notifyOver: function (ddSource, e, data)
408 576 {
409   - if (data.records[0].data.nodeType == 'localParam' && data.records[0].get('notyet'))
410   - {
  577 + if (!downloadCont.doNotifyDrop(data.records[0])) {
411 578 this.valid = false;
412 579 return this.dropNotAllowed;
413 580 }
414   - if (((data.records[0].data.nodeType == 'localParam') ||
415   - (data.records[0].data.nodeType == 'remoteParam') ||
416   - (data.records[0].data.nodeType == 'remoteSimuParam') ||
417   - (data.records[0].data.nodeType == 'derivedParam') ||
418   - (data.records[0].data.nodeType == 'myDataParam') ||
419   - (data.records[0].data.nodeType == 'alias')) &&
420   - (data.records[0].isLeaf() || data.records[0].data.isParameter) &&
421   - !data.records[0].data.disable)
422   - {
423   - this.valid = true;
424   - return this.dropAllowed;
425   - }
426   -
427   - this.valid = false;
428   - return this.dropNotAllowed;
  581 + this.valid = true;
  582 + return this.dropAllowed;
429 583 },
430 584 notifyDrop: function (ddSource, e, data)
431 585 {
432 586 if (!this.valid)
433 587 return false;
434   - var idToSent;
435   - var components = null;
436   - var predefinedArgs = data.records[0].get('predefinedArgs');
437   - switch (data.records[0].data.nodeType)
438   - {
439   - case 'localParam' :
440   - case 'remoteParam':
441   - case 'remoteSimuParam':
442   - idToSent = data.records[0].get('id');
443   - if (data.records[0].get('alias') != "")
444   - idToSent = "#" + data.records[0].get('alias');
445   - var component_info = data.records[0].get('component_info');
446   - if (component_info && component_info.parentId)
447   - {
448   - if (component_info.index1 || component_info.index2)
449   - {
450   - idToSent = component_info.parentId;
451   - components = [];
452   - if (component_info.index1)
453   - components['index1'] = component_info.index1;
454   - if (component_info.index2)
455   - components['index2'] = component_info.index2;
456   - predefinedArgs = data.records[0].parentNode.get('predefinedArgs');
457   - }
458   - if (data.records[0].get('needsArgs'))
459   - {
460   - idToSent = component_info.parentId;
461   - if (component_info.index1)
462   - {
463   - components = [];
464   - components['index1'] = component_info.index1;
465   - }
466   - }
467   - }
468   - break;
469   - case 'alias' :
470   - idToSent = "#" + data.records[0].get('text');
471   - break;
472   - case 'derivedParam' :
473   - if (data.records[0].modelName == 'amdaModel.DerivedParamComponentNode')
474   - {
475   - paramId = data.records[0].get('text');
476   - var parentId = paramId.substr(0, paramId.length - 3);
477   - idToSent = "ws_" + parentId;
478   - var regExp = /\(([\d]+)\)/;
479   - var component_index = regExp.exec(paramId);
480   - if (component_index)
481   - {
482   - components = [];
483   - components['index1'] = component_index[1];
484   - }
485   - break;
486   - } else
487   - {
488   - idToSent = "ws_" + data.records[0].get('text');
489   - }
490   - break;
491   - case 'myDataParam' :
492   - if (data.records[0].modelName == 'amdaModel.MyDataParamComponentNode')
493   - {
494   - paramId = data.records[0].get('text');
495   - var parentId = paramId.substr(0, paramId.length - 3);
496   - idToSent = "wsd_" + parentId;
497   - var regExp = /\(([\d]+)\)/;
498   - var component_index = regExp.exec(paramId);
499   - if (component_index)
500   - {
501   - components = [];
502   - components['index1'] = component_index[1];
503   - }
504   - break;
505   - }
506   - else{
507   - idToSent = "wsd_" + data.records[0].get('text');
508   - }
509   - break;
510   - default :
511   - return false;
512   - }
513   - var downModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.download.id);
514   - if (downModule) {
515   -
516   - if (predefinedArgs) {
517   - downModule.parseTemplatedParam(idToSent, function(param_info) {
518   - downModule.addParam(param_info.paramid, data.records[0].get('leaf'), data.records[0].get('needsArgs'), components, param_info.template_args);
519   - });
520   - }
521   - else {
522   - downModule.addParam(idToSent, data.records[0].get('leaf'), data.records[0].get('needsArgs'), components);
523   - return true;
524   - }
525   - }
526   - return true;
  588 + return downloadCont.doParamDrop(data.records[0]);
527 589 }
528 590 });
529 591 }
... ... @@ -587,11 +649,10 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
587 649  
588 650 var storeTimeFormat = new Ext.data.ArrayStore({
589 651 fields: ['id', 'name', 'qtip'],
590   - data: this.timeformatData
  652 + data: amdaModel.DownloadConfig.timeformatData
591 653 });
592 654  
593   - this.paramPanel = {
594   - xtype: 'container',
  655 + this.paramPanel = new Ext.container.Container({
595 656 title: 'Parameters',
596 657 layout: {
597 658 type: 'hbox',
... ... @@ -607,12 +668,7 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
607 668 align: 'stretch'
608 669 },
609 670 items: [
610   - {
611   - xtype: 'textfield',
612   - fieldLabel: 'Request Name',
613   - disabled: true,
614   - name: 'name'
615   - },
  671 + this.fieldName,
616 672 {
617 673 xtype: 'splitter',
618 674 flex: 0.05
... ... @@ -647,14 +703,12 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
647 703 '<li class="x-boundlist-item" data-qtip="{qtip}">{name}</li>',
648 704 '</tpl>'
649 705 ]
650   - },
651   - value: storeTimeFormat.first()
  706 + }
652 707 },
653 708 {
654 709 fieldLabel: 'File Structure',
655 710 name: 'filestructure',
656   - store: this.filestructureData,
657   - value: this.filestructureData[2],
  711 + store: amdaModel.DownloadConfig.filestructureData,
658 712 listeners: {
659 713 change: {fn: this.onFileStructureChange},
660 714 scope: this
... ... @@ -669,7 +723,7 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
669 723 {
670 724 xtype: 'checkbox', boxLabel: 'Use first param. as reference for sampling',
671 725 boxLabelAlign: 'before',
672   - name: 'refparamsampling', checked: false, disabled: true,
  726 + name: 'refparamSampling', checked: false, disabled: true,
673 727 listeners: {
674 728 change: {fn: this.onRefParamSamplingChange},
675 729 scope: this
... ... @@ -694,19 +748,17 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
694 748 {
695 749 fieldLabel: 'File Format',
696 750 name: 'fileformat',
697   - store: this.fileformatData,
698   - value: this.fileformatData[0]
  751 + store: amdaModel.DownloadConfig.fileformatData
699 752 },
700 753 {
701 754 fieldLabel: 'Compression',
702 755 name: 'compression',
703   - store: this.filecompressData,
704   - value: this.filecompressData[0]
  756 + store: amdaModel.DownloadConfig.filecompressData
705 757 },
706 758 this.timeSelector
707 759 ]
708 760 }
709   - ]};
  761 + ]});
710 762  
711 763 this.ttPanel =
712 764 {
... ... @@ -745,20 +797,17 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
745 797 '<li class="x-boundlist-item" data-qtip="{qtip}">{name}</li>',
746 798 '</tpl>'
747 799 ]
748   - },
749   - value: storeTimeFormat.first()
  800 + }
750 801 },
751 802 {
752 803 fieldLabel: 'File Format ',
753 804 name: 'fileformatTT',
754   - store: this.fileformatTTData,
755   - value: this.fileformatTTData[0]
  805 + store: amdaModel.DownloadConfig.fileformatTTData
756 806 },
757 807 {
758 808 fieldLabel: 'Compression ',
759 809 name: 'compressionTT',
760   - store: this.filecompressTT,
761   - value: this.filecompressTT[0]
  810 + store: amdaModel.DownloadConfig.filecompressTTData
762 811 }
763 812 ]}
764 813 ]
... ... @@ -780,8 +829,16 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
780 829 items: [
781 830 this.paramPanel,
782 831 this.ttPanel
783   - ]
784   - }],
  832 + ],
  833 + listeners: {
  834 + tabchange: function(tabPanel, newCard, oldCard, eOpts) {
  835 + var saveBtn = this.down('#save-download');
  836 + saveBtn.setDisabled(newCard != this.paramPanel);
  837 + },
  838 + scope: this
  839 + }
  840 + },
  841 + ],
785 842 fbar: [
786 843 {
787 844 text: 'Download',
... ... @@ -798,17 +855,19 @@ Ext.define(&#39;amdaUI.DownloadUI&#39;, {
798 855 text: 'Reset',
799 856 scope: this,
800 857 handler: function () {
801   - this.formPanel.getForm().reset();
802   - var tabPanel = this.formPanel.down();
803   - var downloadSrc = tabPanel.items.indexOf(tabPanel.getActiveTab());
804   - if (downloadSrc === 0) {
805   - // reset parameters and Time Tables in Get Data
806   - this.paramGrid.store.removeAll();
807   - this.timeSelector.TTGrid.store.removeAll();
808   - } else {
809   - // reset Time Tables in Get time Table
810   - this.TTGrid.store.removeAll();
811   - }
  858 + var downModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.download.id);
  859 + downModule.createLinkedNode();
  860 + var obj = null;
  861 + downModule.createObject(obj);
  862 + this.setObject(downModule.linkedNode.get('object'));
  863 + }
  864 + },
  865 + {
  866 + text: 'Save',
  867 + id: 'save-download',
  868 + scope: this,
  869 + handler: function () {
  870 + this.saveRequest();
812 871 }
813 872 },
814 873 '->',
... ...
js/app/views/ExplorerUI.js
... ... @@ -588,6 +588,7 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, {
588 588 case 'catalog' :
589 589 case 'request' :
590 590 case 'condition' :
  591 + case 'download':
591 592 record.editLeaf();
592 593 break;
593 594 case 'localParam' :
... ...
js/app/views/ParameterUI.js
... ... @@ -391,7 +391,14 @@ Ext.define(&#39;amdaUI.ParameterUI&#39;,
391 391 }
392 392 var paramModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.param.id);
393 393 if (paramModule) {
394   - paramModule.addParam(nameToSent, data.records[0].get('leaf'), data.records[0].get('needsArgs'), components);
  394 + if (data.records[0].get('predefinedArgs')) {
  395 + paramModule.parseTemplatedParam(nameToSent, function(param_info) {
  396 + paramModule.addParam(param_info.paramid, data.records[0].get('leaf'), true, components, param_info.template_args);
  397 + });
  398 + }
  399 + else {
  400 + paramModule.addParam(nameToSent, data.records[0].get('leaf'), data.records[0].get('needsArgs'), components);
  401 + }
395 402 }
396 403 return true;
397 404 }
... ...
js/app/views/PlotComponents/PlotPanelForm.js
... ... @@ -129,10 +129,10 @@ Ext.define(&#39;amdaPlotComp.PlotPanelForm&#39;, {
129 129 me.updateOptions(value);
130 130 }
131 131 }),
132   - this.addStandardCheck('panel-scatter-isotropic', 'Isotropic', function(name, value, oldValue) {
  132 + this.addStandardCheck('panel-scatter-isotropic', 'Orthonormal scale', function(name, value, oldValue) {
133 133 me.object.set('panel-scatter-isotropic', value);
134 134 me.crtTree.refresh();
135   - }),
  135 + }, 'When this option is selected, X-axis and Y-axis appear with the same scale in the panel'),
136 136 this.addStandardText('panel-epoch-centertimeid', 'Epoch Center Time Id', function(name, value, oldValue) {
137 137 me.object.set('panel-epoch-centertimeid', value);
138 138 me.crtTree.refresh();
... ...
js/app/views/PlotComponents/PlotStandardForm.js
... ... @@ -167,21 +167,30 @@ Ext.define(&#39;amdaPlotComp.PlotStandardForm&#39;, {
167 167 };
168 168 },
169 169  
170   - addStandardCheck: function(name, label, onChange) {
  170 + addStandardCheck: function(name, label, onChange, tooltip) {
  171 +
171 172 return {
172   - xtype: 'checkbox',
173   - name: name,
174   - boxLabel: label,
175   - listeners: {
176   - change: function(combo, newValue, oldValue, eOpts) {
177   -
178   - this.object.set(name, newValue);
179   - if (onChange != null)
180   - onChange(name, newValue, oldValue);
181   - },
182   - scope: this
183   - }
184   - };
  173 + xtype: 'checkbox',
  174 + name: name,
  175 + boxLabel: label,
  176 + listeners: {
  177 + change: function(combo, newValue, oldValue, eOpts) {
  178 + this.object.set(name, newValue);
  179 + if (onChange != null)
  180 + onChange(name, newValue, oldValue);
  181 + },
  182 + render: function(c) {
  183 + if (tooltip) {
  184 + Ext.create('Ext.tip.ToolTip', {
  185 + target: c.getEl(),
  186 + dismissDelay: 0,
  187 + html: tooltip
  188 + });
  189 + }
  190 + },
  191 + scope: this
  192 + }
  193 + };
185 194 },
186 195  
187 196 addStandardFieldSet: function(title, checkboxName, items, onChangeCheck) {
... ...
js/app/views/PlotComponents/PlotTabContent.js
... ... @@ -167,9 +167,8 @@ Ext.define(&#39;amdaPlotComp.PlotTabContent&#39;, {
167 167 },
168 168  
169 169 getDataProcess : function() {
170   - var downObject = amdaModel.DownloadNode.decodeObject(this.plotNode.get('object'));
171   - amdaModel.DownloadNode.set('object',Ext.create('amdaModel.Download',downObject));
172   - amdaModel.DownloadNode.editInModule();
  170 + var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
  171 + plotModule.editInDownloadModule(this.plotNode);
173 172 },
174 173  
175 174 isValidRequest : function(acceptEmptyTTList = true) {
... ...
js/app/views/SearchUI.js
... ... @@ -414,8 +414,16 @@ Ext.define(&#39;amdaUI.SearchUI&#39;,
414 414 }
415 415 var searchModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.search.id);
416 416  
417   - if (searchModule)
418   - searchModule.addParam(nameToSent, data.records[0].get('leaf'), data.records[0].get('needsArgs'), components);
  417 + if (searchModule) {
  418 + if (data.records[0].get('predefinedArgs')) {
  419 + searchModule.parseTemplatedParam(nameToSent, function(param_info) {
  420 + searchModule.addParam(param_info.paramid, data.records[0].get('leaf'), true, components, param_info.template_args);
  421 + });
  422 + }
  423 + else {
  424 + searchModule.addParam(nameToSent, data.records[0].get('leaf'), data.records[0].get('needsArgs'), components);
  425 + }
  426 + }
419 427 return true;
420 428 }
421 429 });
... ...
js/app/views/StatisticsUI.js
... ... @@ -370,7 +370,14 @@ Ext.define(&#39;amdaUI.StatisticsUI&#39;,
370 370 var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.statistics.id);
371 371 if (module)
372 372 {
373   - module.addParam(nameToSent, data.records[0].get('leaf'), data.records[0].get('needsArgs'), components);
  373 + if (data.records[0].get('predefinedArgs')) {
  374 + module.parseTemplatedParam(nameToSent, function(param_info) {
  375 + module.addParam(param_info.paramid, data.records[0].get('leaf'), true, components, param_info.template_args);
  376 + });
  377 + }
  378 + else {
  379 + module.addParam(nameToSent, data.records[0].get('leaf'), data.records[0].get('needsArgs'), components);
  380 + }
374 381 }
375 382 return true;
376 383 }
... ...
js/app/views/TimeTableUI.js
... ... @@ -194,7 +194,7 @@ Ext.define(&#39;amdaUI.TimeTableUI&#39;, {
194 194 // synchronisation of objects
195 195 this.object = ttobj;
196 196 timeTableModule.linkedNode.create();
197   - } else if (this.fclose()) /*TimeTable object has been modified*/
  197 + } else if (this.fclose() || this.status && (this.status.nbFiltered > 0)) /*TimeTable object has been modified*/
198 198 {
199 199 if (this.object.isModified('name') || this.object.get('fromPlugin'))
200 200 {
... ...
php/RemoteDataCenter/ImpexParamManager.php
... ... @@ -380,7 +380,7 @@ class ImpexParamManager
380 380 $obj = (object)array(
381 381 "nodeType" => "download",
382 382 "downloadSrc" => "0",
383   - "structure" => 2,
  383 + "filestructure" => 2,
384 384 "refparamSampling" => false,
385 385 "sampling" => 60,
386 386 "timesrc" => "Interval",
... ...
php/classes/AmdaAction.php
... ... @@ -10,7 +10,7 @@ class AmdaAction
10 10 'remoteSimuParam' => 'RemoteParams.xml', 'derivedParam' => 'WsParams.xml', 'myDataParam' => 'WsParams.xml',
11 11 'timeTable' => 'Tt.xml', 'catalog' => 'Tt.xml', 'alias' => 'Alias.xml',
12 12 'myData' => 'Files.xml',
13   - 'request' => 'Request.xml', 'condition' => 'Request.xml',
  13 + 'request' => 'Request.xml', 'condition' => 'Request.xml', 'download' => 'Request.xml',
14 14 'bkgWorks' => 'jobs.xml');
15 15  
16 16 private $user, $amdaStat;
... ... @@ -169,21 +169,12 @@ class AmdaAction
169 169 ];
170 170 break;
171 171  
  172 + case 'download':
172 173 case 'condition':
173   - $objectMgr = new RequestMgr($nodeType);
174   - $info = $objectMgr->getObject($id)->expression;
175   - break;
176   -
177 174 case 'request':
178   - $objectMgr = new RequestMgr($nodeType);
179   - $objplot = $objectMgr->getObject($id);
180   - if (isset($objplot->name)) {
181   - $info = $objplot->name;
182   - }
183   - else {
184   - $info = $id;
185   - }
186   - break;
  175 + $objectMgr = new RequestMgr($nodeType);
  176 + $info = $objectMgr->getObjectInfo($id);
  177 + break;
187 178  
188 179 case 'timeTable':
189 180 case 'catalog':
... ... @@ -664,6 +655,7 @@ class AmdaAction
664 655 $result = $this->executeRequest((Object) array(
665 656 'compression' => 'none',
666 657 'fileformat' => 'internal',
  658 + 'timeformat' => 'YYYY-MM-DDThh:mm:ss',
667 659 'sendToSamp' => FALSE,
668 660 'list' => array(
669 661 (Object) array(
... ... @@ -742,6 +734,7 @@ class AmdaAction
742 734 break;
743 735 case 'condition' :
744 736 case 'request' :
  737 + case 'download' :
745 738 $objectMgr = new RequestMgr($nodeType);
746 739 break;
747 740 case 'bkgWorks' :
... ... @@ -775,6 +768,7 @@ class AmdaAction
775 768 break;
776 769 case 'condition' :
777 770 case 'request' :
  771 + case 'download' :
778 772 $objectMgr = new RequestMgr($obj->nodeType);
779 773 break;
780 774 case 'alias' :
... ... @@ -813,6 +807,7 @@ class AmdaAction
813 807 break;
814 808 case 'condition' :
815 809 case 'request' :
  810 + case 'download' :
816 811 $objectMgr = new RequestMgr($obj->nodeType);
817 812 break;
818 813 case 'alias' :
... ... @@ -846,6 +841,7 @@ class AmdaAction
846 841 break;
847 842 case 'condition' :
848 843 case 'request' :
  844 + case 'download' :
849 845 $objectMgr = new RequestMgr($obj->nodeType);
850 846 break;
851 847 case 'alias' :
... ... @@ -876,6 +872,7 @@ class AmdaAction
876 872 break;
877 873 case 'condition' :
878 874 case 'request' :
  875 + case 'download' :
879 876 $objectMgr = new RequestMgr($obj->nodeType);
880 877 break;
881 878 default:
... ... @@ -902,6 +899,7 @@ class AmdaAction
902 899 break;
903 900 case 'condition' :
904 901 case 'request' :
  902 + case 'download' :
905 903 $objectMgr = new RequestMgr($obj->nodeType);
906 904 break;
907 905 default:
... ...
php/classes/Guest.php
... ... @@ -7,117 +7,156 @@
7 7  
8 8 class Guest {
9 9  
10   - private $guestXml, $guestXmlFile, $xp, $root;
  10 + private $guestXmlFile;
11 11 public $Id, $Start, $Ip, $email;
12 12  
13 13 function __construct($Ip_, $email_ = null){
14   -
15 14 if($email_) {
16   - $this->Start = getdate();
17   - $this->Ip = $Ip_;
18   - $this->email = $email_;
19   - }
20   - else {
21   - $this->Id = substr($Ip_,strlen("guest"));
22   - }
23   -
24   - $this->guestXmlFile = DATAPATH."guests.xml";
25   - $this->guestXml = new DomDocument("1.0");
26   -
27   - if (!file_exists($this->guestXmlFile)){
28   - $status = $this->generateXML();
29   - }
30   - else {
31   - $this->guestXml->load($this->guestXmlFile);
32   - $this->root = $this->guestXml->getElementsByTagName("guests")->item(0);
  15 + $this->Start = getdate();
  16 + $this->Ip = $Ip_;
  17 + $this->email = $email_;
33 18 }
34   - $this->xp = new domxpath($this->guestXml);
  19 + else {
  20 + $this->Id = substr($Ip_,strlen("guest"));
  21 + }
  22 +
  23 + $this->guestXmlFile = DATAPATH."guests.xml";
  24 + }
  25 +
  26 + public function checkGuestTimes() {
  27 + return $this->concurrentAccessGuestFile(array($this,'_checkGuestTimes'));
  28 + }
  29 +
  30 + public function deleteGuest() {
  31 + return $this->concurrentAccessGuestFile(array($this,'_deleteGuest'));
  32 + }
  33 +
  34 + public function addGuest(){
  35 + return $this->concurrentAccessGuestFile(array($this,'_addGuest'));
35 36 }
36 37  
37   - private function generateXML() {
38   - $this->root = $this->guestXml->createElement('guests');
39   - $this->guestXml->appendChild($this->root);
  38 + public function registerGuest(){
  39 + return $this->concurrentAccessGuestFile(array($this,'_registerGuest'));
  40 + }
  41 +
  42 + private function concurrentAccessGuestFile($callback) {
  43 + $lockFile = $this->guestXmlFile.".lockfile";
  44 +
  45 + $fp = fopen($lockFile, "w+");
  46 +
  47 + if ($fp === false) {
  48 + return false;
  49 + }
40 50  
41   - $status = $this->guestXml->save($this->guestXmlFile);
  51 + $res = true;
42 52  
43   - return $status;
  53 + if (flock($fp, LOCK_EX))
  54 + {
  55 + if (!file_exists($this->guestXmlFile)) {
  56 + $res = $this->_generateXML();
  57 + }
  58 +
  59 + if ($res) {
  60 + $dom = new DomDocument("1.0","UTF-8");
  61 + $dom->preserveWhiteSpace = false;
  62 + $dom->formatOutput = true;
  63 + $res = $dom->load($this->guestXmlFile);
  64 + if ($res) {
  65 + $func_res = call_user_func($callback,$dom);
  66 + }
  67 + }
  68 + }
  69 + else
  70 + $res = false;
  71 +
  72 + fclose($fp);
  73 +
  74 + if ($res)
  75 + return $func_res;
  76 +
  77 + return false;
  78 + }
  79 +
  80 + private function _generateXML() {
  81 + $dom = new DOMDocument("1.0","UTF-8");
  82 + $dom->preserveWhiteSpace = false;
  83 + $dom->formatOutput = true;
  84 + $rootNode = $dom->createElement('guests');
  85 + $dom->appendChild($rootNode);
  86 + return $dom->save($this->guestXmlFile);
44 87 }
45 88  
46   - public function GetId(){
47   -
48   - $elements = $this->xp->query("//@xml:id");
  89 + private function _getId($dom){
  90 + $xp = new DOMXpath($dom);
  91 + $elements = $xp->query("//@xml:id");
49 92 // Now find New Valid ID
50   - if ($elements->length > 0) {
51   - $idList = array();
52   - for ($i = 0; $i < $elements->length; $i++)
53   - $idList[$i] = $elements->item($i)->nodeValue;
  93 + if ($elements->length > 0) {
  94 + $idList = array();
  95 + for ($i = 0; $i < $elements->length; $i++)
  96 + $idList[$i] = $elements->item($i)->nodeValue;
54 97  
55   - sort($idList);
56   - for ($i = 0; $i < $elements->length; $i++) {
57   - if ($idList[$i] > $i) {
58   - $newID = $i;
59   - break;
60   - }
61   - $newID = $i+1;
62   - }
63   - } else { $newID = 0;}
64   -
65   - return $newID;
66   - }
67   -
68   - public function checkGuestTimes(){
69   -
70   - $Start_0 = time() - GuestSessionDuration*60; // in secs
71   - $startTimes = $this->xp->query("//guest[@start<".$Start_0."]/@xml:id");
72   -
73   - if ($startTimes->length > 0) {
  98 + sort($idList);
  99 + for ($i = 0; $i < $elements->length; $i++) {
  100 + if ($idList[$i] > $i) {
  101 + $newID = $i;
  102 + break;
  103 + }
  104 + $newID = $i+1;
  105 + }
  106 + } else { $newID = 0;}
  107 +
  108 + return $newID;
  109 + }
  110 +
  111 + private function _checkGuestTimes($dom){
  112 + $xp = new DOMXpath($dom);
  113 + $Start_0 = time() - GuestSessionDuration*60; // in secs
  114 + $startTimes = $xp->query("//guest[@start<".$Start_0."]/@xml:id");
  115 +
  116 + if ($startTimes->length > 0) {
74 117 for ($i = 0; $i < $startTimes->length; $i++) {
75   - $user = "guest".$startTimes->item($i)->value;
76   - $this->deltree(USERPATH.$user);
77   - $this->root->removeChild($startTimes->item($i)->parentNode);
  118 + $user = "guest".$startTimes->item($i)->value;
  119 + $this->_deltree(USERPATH.$user);
  120 + $dom->documentElement->removeChild($startTimes->item($i)->parentNode);
78 121 }
79   - $this->xp = new domxpath($this->guestXml);
80   - }
81 122  
  123 + return $dom->save($this->guestXmlFile);
  124 + }
  125 + return true;
82 126 }
83 127  
84   - public function deleteGuest(){
85   -
86   - $user = "guest".$this->Id;
87   - $this->deltree(USERPATH.$user);
88   - $theGuest = $this->guestXml->getElementById($this->Id);
89   - $this->root->removeChild($theGuest);
90   - $this->guestXml->save($this->guestXmlFile);
91   -
92   - }
  128 + private function _deleteGuest($dom){
  129 + $user = "guest".$this->Id;
  130 + $this->_deltree(USERPATH.$user);
  131 + $theGuest = $dom->getElementById($this->Id);
  132 + $dom->documentElement->removeChild($theGuest);
  133 + return $dom->save($this->guestXmlFile);
  134 + }
93 135  
94   - public function addGuest(){
95   -
96   - if (($this->Id = $this->GetId()) < MaxGuests) {
97   - $guest = $this->guestXml->createElement("guest");
98   - $guest->setAttribute('xml:id',$this->Id );
99   - $guest->setAttribute('start',time());
100   - $guest->appendChild($this->guestXml->createElement("IP", $this->Ip));
101   - $guest->appendChild($this->guestXml->createElement("email", $this->email));
102   - $this->root->appendChild($guest);
103   - $this->guestXml->save($this->guestXmlFile);
104   -
105   - return "guest".$this->Id;
106   - }
107   - else {
108   - return "allGuestLoginsInUse";
109   - }
110   - }
111   -
112   - public function registerGuest(){
113   -
114   - $guest_file = fopen(DATAPATH.'guest.login','a');
115   - fwrite($guest_file, $this->email." ".$this->Ip." ".$this->Start['mday']."/".$this->Start['mon']."/".$this->Start['year']."\n");
116   - fclose($guest_file);
  136 + private function _addGuest($dom){
  137 + if (($this->Id = $this->_getId($dom)) < MaxGuests) {
  138 + $guest = $dom->createElement("guest");
  139 + $guest->setAttribute('xml:id',$this->Id );
  140 + $guest->setAttribute('start',time());
  141 + $guest->appendChild($dom->createElement("IP", $this->Ip));
  142 + $guest->appendChild($dom->createElement("email", $this->email));
  143 + $dom->documentElement->appendChild($guest);
  144 + $dom->save($this->guestXmlFile);
  145 + return "guest".$this->Id;
  146 + }
  147 + else {
  148 + return "allGuestLoginsInUse";
  149 + }
  150 + }
117 151  
  152 + private function _registerGuest($dom){
  153 + $guest_file = fopen(DATAPATH.'guest.login','a');
  154 + fwrite($guest_file, $this->email." ".$this->Ip." ".$this->Start['mday']."/".$this->Start['mon']."/".$this->Start['year']."\n");
  155 + fclose($guest_file);
  156 + return true;
118 157 }
119 158  
120   - public function deltree($f) {
  159 + private function _deltree($f) {
121 160  
122 161 if (is_dir($f)) {
123 162  
... ... @@ -125,7 +164,7 @@ class Guest {
125 164  
126 165 foreach($files as $sf) {
127 166 if (is_dir("$f/$sf") && !is_link("$f/$sf")) {
128   - $this->deltree("$f/$sf");
  167 + $this->_deltree("$f/$sf");
129 168 } else {
130 169 unlink("$f/$sf");
131 170 }
... ...
php/classes/RequestMgr.php
... ... @@ -9,7 +9,7 @@ class RequestMgr extends AmdaObjectMgr
9 9 public $obj;
10 10 protected $type;
11 11 protected $jobXml, $jobXmlName;
12   - protected $types = array('request', 'condition');
  12 + protected $types = array('request', 'download', 'condition');
13 13  
14 14 function __construct($type)
15 15 {
... ... @@ -34,6 +34,10 @@ class RequestMgr extends AmdaObjectMgr
34 34 {
35 35 $this->id_prefix = 'req_';
36 36 }
  37 + else if ($type == 'download' )
  38 + {
  39 + $this->id_prefix = 'down_';
  40 + }
37 41 else
38 42 {
39 43 $this->id_prefix = 'cond_';
... ... @@ -173,17 +177,14 @@ class RequestMgr extends AmdaObjectMgr
173 177 if ($this->type == 'condition')
174 178 {
175 179 $p->expression = $this->resetAlias($p->expression);
176   - $info = $p->expression;
177 180 }
178 181 else if ($this->type == 'request')
179 182 {
180   - $info = '';
181 183 for ($i=0; $i < count($p->children); $i++)
182 184 {
183 185 for ($j=0; $j < count($p->children[$i]->children); $j++)
184 186 {
185 187 $p->children[$i]->children[$j]->name = $this->resetAlias($p->children[$i]->children[$j]->name);
186   - $info = $info.' '.$p->children[$i]->children[$j]->name;
187 188 }
188 189 }
189 190 }
... ... @@ -201,7 +202,7 @@ class RequestMgr extends AmdaObjectMgr
201 202  
202 203 $this -> addToContent($p, $folder);
203 204  
204   - return array('id' => $this->id, 'info' => $info, 'last_update' => $p->last_update) + $additional;
  205 + return array('id' => $this->id, 'info' => $this->getObjectInfo($p->id), 'last_update' => $p->last_update) + $additional;
205 206 }
206 207  
207 208 public static function checkRequest($obj)
... ... @@ -351,5 +352,87 @@ class RequestMgr extends AmdaObjectMgr
351 352  
352 353 return array('success' => true);
353 354 }
  355 +
  356 + public function getObjectInfo($id) {
  357 + $info = "Request ID: ".$id."<br/>";
  358 +
  359 + if (!file_exists(USERREQDIR.$id)) {
  360 + $info .= "<b>ERROR:</b> Cannot retrieve request definition file";
  361 + return $info;
  362 + }
  363 +
  364 + $obj = json_decode(file_get_contents(USERREQDIR.$id));
  365 + if (empty($obj)) {
  366 + $info .= "<b>ERROR:</b> Cannot load request definition file";
  367 + return $info;
  368 + }
  369 +
  370 + switch ($this->type) {
  371 + case 'request':
  372 + $info .= "Plot: ";
  373 + $panels_list = array();
  374 + if (!empty($obj->panels)) {
  375 + foreach ($obj->panels as $p) {
  376 + $panel_info = "Panel #".$p->{"panel-index"}.": ";
  377 + if (empty($p->params)) {
  378 + $panel_info .= "Empty";
  379 + }
  380 + else {
  381 + $params_list = array();
  382 + if (!empty($p->params)) {
  383 + foreach ($p->params as $p) {
  384 + if (!in_array($p->paramid, $params_list))
  385 + $params_list[] = $p->paramid;
  386 + }
  387 + }
  388 + if (!empty($params_list)) {
  389 + $panel_info .= implode(', ', $params_list);
  390 + }
  391 + else {
  392 + $panel_info .= "Empty";
  393 + }
  394 + }
  395 + $panels_list[] = $panel_info;
  396 + }
  397 + }
  398 + if (!empty($panels_list)) {
  399 + $info .= '<br/>'.implode('<br/>', $panels_list);
  400 + }
  401 + else {
  402 + $info .= "Empty";
  403 + }
  404 + break;
  405 + case 'condition':
  406 + $info .= "Data Mining: ".htmlspecialchars($obj->expression);
  407 + break;
  408 + case 'download':
  409 + $info .= "Download: ";
  410 + $params_list = array();
  411 + if (!empty($obj->list)) {
  412 + foreach ($obj->list as $p) {
  413 + if (!in_array($p->paramid, $params_list))
  414 + $params_list[] = $p->paramid;
  415 + }
  416 + }
  417 + if (!empty($params_list)) {
  418 + $info .= implode(', ',$params_list);
  419 + }
  420 + else {
  421 + $info .= "Empty";
  422 + }
  423 + break;
  424 + default:
  425 + $info .= "<b>ERROR:</b> Unknown request type";
  426 + }
  427 +
  428 + return $info;
  429 + }
  430 +
  431 + function modifyObject($p)
  432 + {
  433 + $result = parent::modifyObject($p);
  434 + $result["info"] = $this->getObjectInfo($p->id);
  435 + return $result;
  436 + }
354 437 }
355 438 ?>
... ...
php/classes/UserMgr.php
... ... @@ -704,9 +704,6 @@ class UserMgr
704 704  
705 705 protected function updateTreeForGrpsAndTimeRestrictions($file)
706 706 {
707   - if (!isset($this->userGrps))
708   - return TRUE;
709   -
710 707 $xml = new DomDocument("1.0");
711 708  
712 709 if(!$xml->load($file))
... ... @@ -714,18 +711,20 @@ class UserMgr
714 711  
715 712 $xp = new domxpath($xml);
716 713  
717   - foreach ($this->userGrps as $grp) {
718   - $nodes = $xp->query("//*[@group='".$grp."']");
  714 + if (!empty($this->userGrps)) {
  715 + foreach ($this->userGrps as $grp) {
  716 + $nodes = $xp->query("//*[@group='".$grp."']");
719 717  
720   - if ($nodes->length > 0)
721   - foreach ($nodes as $node) {
722   - $node->removeAttribute('group');
723   - if ($node->hasAttribute('restriction')) {
724   - if ($node->getAttribute('restriction') != "plotOnly") {
725   - $node->removeAttribute('restriction');
  718 + if ($nodes->length > 0)
  719 + foreach ($nodes as $node) {
  720 + $node->removeAttribute('group');
  721 + if ($node->hasAttribute('restriction')) {
  722 + if ($node->getAttribute('restriction') != "plotOnly") {
  723 + $node->removeAttribute('restriction');
  724 + }
726 725 }
727   - }
728   - }
  726 + }
  727 + }
729 728 }
730 729  
731 730 if (!empty($this->datasetsTimeRestriction)) {
... ...